No description
  • Go 97.8%
  • Makefile 1.3%
  • Dockerfile 0.9%
Find a file
2026-04-28 10:53:14 +07:00
checker Initial commit 2026-04-28 10:53:14 +07:00
contract Initial commit 2026-04-28 10:53:14 +07:00
plugin Initial commit 2026-04-28 10:53:14 +07:00
.gitignore Initial commit 2026-04-28 10:53:14 +07:00
Dockerfile Initial commit 2026-04-28 10:53:14 +07:00
go.mod Initial commit 2026-04-28 10:53:14 +07:00
go.sum Initial commit 2026-04-28 10:53:14 +07:00
LICENSE Initial commit 2026-04-28 10:53:14 +07:00
main.go Initial commit 2026-04-28 10:53:14 +07:00
Makefile Initial commit 2026-04-28 10:53:14 +07:00
NOTICE Initial commit 2026-04-28 10:53:14 +07:00
README.md Initial commit 2026-04-28 10:53:14 +07:00

checker-dangling

A happyDomain checker that scans a working zone for dangling subdomains: records (CNAME / MX / SRV / NS) whose targets resolve to NXDOMAIN, or whose external registrable domain is expired, in pendingDelete, or recently re-registered. This is the attack class popularised by Ars Technica in 2017, where universities ended up serving porn from CNAMEs that pointed at decommissioned third-party services after malicious actors re-registered the lapsed targets.

It runs in three deployment modes (standalone HTTP binary, Go plugin, Docker image), like every other checker in the happyDomain ecosystem.

How it works

The checker walks every service in the working zone (AutoFillZone) and extracts pointer records from svcs.CNAME, svcs.SpecialCNAME, svcs.MXs, svcs.UnknownSRV, and svcs.Orphan bodies (the latter covering bare NS/CNAME/MX records when no dedicated service is attached). For each (owner, rrtype, target) triple it:

  1. Classifies the target as in-zone or external relative to the zone's eTLD+1 (via golang.org/x/net/publicsuffix).
  2. Performs a single, time-bounded DNS resolution to detect immediate breakage (nxdomain, servfail, no_answer, timeout).
  3. Publishes a DiscoveryEntry per pointer:
    • dangling.external-target.v1 for external pointers — companion checkers (notably the host's domain_expiry) subscribe to this type and run RDAP/WHOIS on the registrable domain.
    • dangling.in-zone-target.v1 for same-registrable pointers — used as a join key for future reachability checkers (alias / ping / http) that may consume it.

Verdict matrix

Signal Severity Source
Target NXDOMAIN Critical local DNS resolution
Target SERVFAIL Warning local DNS resolution
Target NOERROR with empty answer Info local DNS resolution
Registrable domain expired Critical whois related obs.
Registrable status pendingDelete / redemptionPeriod Critical whois related obs.
Registrable registered within the last 90 days Warning whois related obs.

The rule emits one CheckState per impacted owner and ranks them by descending severity so the report's "Fix this first" card always matches the rule output.

Companion: domain_expiry

For the WHOIS-driven signals to fire, the host's existing domain_expiry checker must be extended to subscribe to dangling.external-target.v1 entries via AutoFillDiscoveryEntries, run RDAP per registrable domain, and publish a per-Ref whois observation. Without that subscription the checker still works as a DNS-only dangling detector.

Build

make            # standalone binary
make plugin     # .so plugin for happyDomain
make docker     # Docker image
make test       # run the unit tests