- Go 98.1%
- Dockerfile 1.2%
- Makefile 0.7%
Hosts that register the provider only for its definition (externalizable checker) construct it with a nil CollectFn. If the local ObservationContext ends up calling Collect, the previous code dereferenced a nil function value and crashed the goroutine. Surface a typed error so rules degrade to a clean StatusError state. |
||
|---|---|---|
| checker | ||
| internal/collect | ||
| plugin | ||
| .gitignore | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| Makefile | ||
| NOTICE | ||
| README.md | ||
checker-dnsviz
DNSSEC checker for happyDomain, implemented as a thin wrapper around DNSViz.
The container ships dnsviz (Python) alongside the Go binary that exposes the
standard happyDomain checker HTTP API (/health, /definition, /collect,
/evaluate, /report).
How it works
For each check run, the Go binary invokes:
dnsviz probe -A . <ancestors…> <domain> | dnsviz grok -t <root-trust-anchor>
The queried name and every ancestor up to the root are passed to
dnsviz probe, in root → leaf order. dnsviz only emits a full analysis
(DNSKEY set, DS at parent, queries) for names listed on the command line;
ancestors stumbled upon implicitly are kept as "stub" entries that grok
ignores. Listing them explicitly is what makes every link of the chain
appear in the report.
dnsviz grok -t <file> is given a BIND-format DNSKEY trust anchor for the
root zone. Without it, the root has no parent to chain against and stays
classified as NOERROR (DNS rcode) instead of SECURE (DNSSEC).
The output is then parsed: per-zone errors and warnings are walked out of
the nested record tree (delegation.errors, dnskey[i].errors,
queries/.../rrsig[j].errors, …) and turned into individual CheckState
entries tagged with the JSON path where they were found. A curated
catalog of common DNSSEC failure scenarios (broken chain, expired RRSIG,
DS digest mismatch, deprecated algorithm, …) is matched against the
findings to generate a "Fix these first" section in the HTML report with
plain-language remediation hints.
The HTML report renders one block per zone in the chain (root → TLD → intermediates → leaf), each with its delegation/DS records, DNSKEY set, authoritative servers, and per-query analysis (RRsets, RRSIG validity, NSEC proofs) so a recursive DNSSEC failure can be located at the exact level, and the exact record, where it broke.
Scope
This checker is intentionally limited to what DNSViz reports. NSEC/NSEC3
zone-walk hardening and NSEC3PARAM iteration policy (RFC 9276) are
delivered by a separate checker-dnssec module.
Usage
Standalone server
make
./checker-dnsviz -listen :8080
Runtime requirements:
dnsvizonPATH(the Python CLI:pip install dnsviz, pluspygraphvizandgraphvizsincednsviz grok -timports the graph module even when only producing JSON).- A BIND-format root DNSKEY trust anchor file. The collector
auto-detects
/usr/share/dnssec-root/trusted-key.key(Alpine'sdnssec-rootpackage, Debian/Ubuntu'sdns-root-dataships an equivalent at/usr/share/dns/root.key); pass-trust-anchors-file <path>to override. Without it, the root zone in the report stays atNOERRORinstead ofSECURE.
Docker
make docker
docker run -p 8080:8080 happydomain/checker-dnsviz
The image bundles dnsviz, pygraphviz, graphviz and the alpine
dnssec-root package, so the trust anchor is in place out of the box.
When ICANN rolls a new root KSK (KSK-2024 is scheduled to begin signing
in late 2026), rebuild the image once the upstream alpine package ships
the new key.
happyDomain plugin
make plugin
# produces checker-dnsviz.so
Options
| Scope | Id | Default | Description |
|---|---|---|---|
| admin | dnsvizBin |
dnsviz |
Path to the dnsviz CLI. |
| admin | probeTimeoutSeconds |
120 |
Hard timeout for dnsviz probe. |
| admin | extraProbeArgs |
-A |
Extra arguments appended verbatim to dnsviz probe. |
| admin | trustAnchorsFile |
/usr/share/dnssec-root/trusted-key.key (auto-detected) |
BIND DNSKEY file passed to dnsviz grok -t. When unset, the collector falls back to the Alpine dnssec-root package path if it exists. |
| domain | domain_name |
auto-fill | Domain to analyse. |
Rules
| Rule | Description |
|---|---|
dnsviz_overall_status |
DNSViz status of the queried domain (SECURE/INSECURE/BOGUS/INDETERMINATE). |
dnsviz_per_zone_status |
One state per zone in the chain (root, TLD, intermediates, leaf). |
dnsviz_zone_errors |
Every error reported by DNSViz, scoped to the zone where it was found. |
dnsviz_zone_warnings |
Every warning reported by DNSViz, scoped to the zone where it was found. |
dnsviz_common_failures |
Pattern-matches findings against a catalog of common DNSSEC failures. |
Licensing
This repository is split into two licensing zones:
| Path | License | Reason |
|---|---|---|
checker/ |
MIT | Pure analysis logic (types, rules, HTML report). Can be imported by third-party Go projects without GPL obligations. |
internal/collect/ |
GPL v2 | Invokes the dnsviz subprocess. Covered by DNSViz's GPL v2 licence. |
main.go, plugin/ |
GPL v2 | Wire the two together; distributed binaries include the GPL layer. |
If you only need the analysis primitives (parse grok output, evaluate rules, render the HTML report), import git.happydns.org/checker-dnsviz/checker and supply your own checker.CollectFn, for example one that calls the HTTP API instead of running DNSViz locally.