# checker-resolver-propagation Worldwide DNS propagation checker for [happyDomain](https://www.happydomain.org/). Probes a curated catalog of public recursive resolvers (Cloudflare, Google, Quad9, OpenDNS, Yandex, regional ISPs, …) across multiple transports (UDP, TCP, DoT, DoH) and regions, then compares their answers to the zone's authoritative nameservers to detect propagation gaps, regional splits, SOA serial drift, stale caches, DNSSEC validation failures, SERVFAIL/NXDOMAIN inconsistencies, and resolver filtering. ## Usage ### Standalone HTTP server ```bash # Build and run make ./checker-resolver-propagation -listen :8080 ``` The server exposes: - `GET /health`: health check - `POST /collect`: collect propagation observations (happyDomain external checker protocol) - `POST /evaluate`: run the evaluation rules against an observation - `POST /report`: extract metrics / HTML report from an observation ### Docker ```bash make docker docker run -p 8080:8080 happydomain/checker-resolver-propagation ``` ### happyDomain plugin ```bash make plugin # produces checker-resolver-propagation.so, loadable by happyDomain as a Go plugin ``` The plugin exposes a `NewCheckerPlugin` symbol returning the checker definition and observation provider, which happyDomain registers in its global registries at load time. ### Versioning The binary, plugin, and Docker image embed a version string overridable at build time: ```bash make CHECKER_VERSION=1.2.3 make plugin CHECKER_VERSION=1.2.3 make docker CHECKER_VERSION=1.2.3 ``` ### happyDomain remote endpoint Set the `endpoint` admin option for the resolver-propagation checker to the URL of the running checker-resolver-propagation server (e.g., `http://checker-resolver-propagation:8080`). happyDomain will delegate observation collection to this endpoint. This checker applies to **service**-level checks and is restricted to the `abstract.Origin` and `abstract.NSOnlyOrigin` services (the zone apex / NS configuration). ## Options | Id | Type | Default | Description | |-----------------------|--------|-------------------------------|------------------------------------------------------------------------------------------------------------------------| | `recordTypes` | string | `SOA,NS,A,AAAA,MX,TXT,CAA` | Comma-separated list of RR types to probe at the apex (and at each `subdomains` entry). | | `subdomains` | string | `www` | Comma-separated list of owner names to probe in addition to the apex (e.g. `www,mail,@`). Empty = apex only. | | `includeFiltered` | bool | `false` | Probe filtering resolvers (malware/family/adblock). Their answers routinely diverge by design. | | `region` | string | `all` | Restrict to a region: `all`, `global`, `na`, `eu`, `asia`, `ru`, `me`. | | `transports` | string | `udp` | Comma-separated transports to probe: `udp`, `tcp`, `dot`, `doh`. Encrypted transports are only used where published. | | `resolverAllowlist` | string | | Comma-separated resolver IDs or IPs to probe exclusively (e.g. `cloudflare,google,9.9.9.9`). Empty = catalog selection.| | `latencyThresholdMs` | uint | `500` | Resolvers averaging above this value emit an info finding. | | `runTimeoutSeconds` | uint | `30` | Hard wall-clock budget for one propagation run. Slower resolvers report as unreachable. | ## Rules | Code | Description | Severity | |----------------------------------------------|-------------------------------------------------------------------------------------------------------------------|---------------------| | `resolver_propagation.selection` | Checks that the current option set selects at least one public resolver. | CRITICAL | | `resolver_propagation.reachable` | Checks that at least one selected resolver answered a query. | CRITICAL | | `resolver_propagation.latency` | Flags resolvers that are unreachable or whose average response time exceeds the configured threshold. | WARNING | | `resolver_propagation.filtered_hit` | Reports filtered resolvers returning a different answer than the consensus (typical blocklist behaviour). | INFO | | `resolver_propagation.consensus` | Checks that public resolvers agree on a single answer for each probed RRset. | WARNING | | `resolver_propagation.matches_authoritative` | Checks that the public consensus matches the answer served by the zone's authoritative nameservers. | CRITICAL | | `resolver_propagation.nxdomain` | Flags RRsets for which some resolvers return NXDOMAIN while others return NOERROR. | CRITICAL | | `resolver_propagation.servfail` | Flags RRsets for which any resolver returns SERVFAIL (usually DNSSEC or reachability failure). | CRITICAL | | `resolver_propagation.regional_split` | Flags regions in which every resolver agrees on an answer that differs from the global consensus. | WARNING | | `resolver_propagation.serial_drift` | Flags disagreement on the SOA serial across unfiltered resolvers. | WARNING | | `resolver_propagation.stale_cache` | Flags resolvers still serving an SOA serial below the one saved by happyDomain. | INFO | | `resolver_propagation.dnssec` | Checks that validating resolvers successfully validate the zone's DNSSEC chain. | CRITICAL | ## License Licensed under the **MIT License** (see `LICENSE`).