102 lines
6.4 KiB
Markdown
102 lines
6.4 KiB
Markdown
# 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`).
|