zonemaster-tools

The JSON API behind the DNS tools on zonemaster.es, the pages next to the Zonemaster test. The GUI lives in CloudHost/zonemaster-gui-es, and Zonemaster itself is in the stock backend.

Endpoint (/tools-api/…) What it does
propagation?domain=&type= Sends the same question to 18 public resolvers worldwide, plus Google with an EDNS Client Subnet from 11 regions. Compares the answers against the zone's authoritative answer, found by walking down from the root.
resolvers?domain=&type=&resolver= Asks 11 resolvers over UDP, TCP and DoH (HTTP/2). Reports latency, rcode and DNSSEC validation (AD bit). resolver adds a public IP of your choice.
security?domain= 14 checks: DNSSEC (asked of four validators), NS diversity, SOA serial consistency, open AXFR, SPF (with RFC 7208 lookup count), DMARC, DKIM (35 common selectors), MX, CAA, MTA-STS, TLS-RPT, BIMI, dangling CNAMEs / takeover-prone targets, and wildcard. Returns a 0–100 score and grade, and stores one history row per change.
security/history?domain= The tracker: past scores and per-check statuses.
infra?domain= CDN/WAF/hosting from CNAMEs and HTTP headers, ASN per IP (Team Cymru), PTR, TLS certificate, and DNS and mail provider.
graph?domain= Nodes and edges: the delegation path from the root, then NS/MX/web names, CNAME chains, IPs and ASNs.
blocklists?domain= Checks 7 Pi-hole/AdGuard lists (AdGuard DNS, StevenBlack, HaGeZi PRO and TIF, OISD small, URLhaus, Phishing Army) the way each blocker matches them, plus 8 filtering resolvers asked live.
blacklists?domain= Checks 6 domain DNSBLs (Spamhaus DBL, SURBL, URIBL…) and 10 IP DNSBLs for each web and mail IP. Queries go straight to each list's own nameservers.

All output is language-neutral: ids, statuses and data, never prose. The GUI writes the sentences in each locale.

Guard rails

  • Only public addresses. A user-supplied resolver, every probed IP and every HTTP connection must be is_global. The jail sits on 10.20.0.0/24 next to every other jail on gringo. tests/test_parsers.py pins this.
  • Rate limit: 30 cost units per client per minute (a blacklist check costs 3), and 12 heavy requests in flight overall. The client comes from X-Real-IP, set by the host nginx.
  • Cache: 20 s for propagation and resolvers, 120 s for everything else.
  • The web probe sends one GET and reads headers only. It never follows a redirect or reads a body.

Run

pkg install python312 py312-sqlite3 py312-dnspython py312-httpx py312-h2
cp -R zmtools /usr/local/zmtools/
cp rc.d/zmtools /usr/local/etc/rc.d/zmtools
pw useradd zmtools -d /var/db/zmtools -s /usr/sbin/nologin
sysrc zmtools_enable=YES zmtools_host=10.20.0.22
service zmtools start

State lives in /var/db/zmtools/:

  • blocklists.sqlite: about 80 MB, rebuilt every 12 h beside the live copy and then swapped in.
  • history.sqlite: the tracker's history.

The log is /var/log/zmtools.log.

Test

python3 -m pytest -q tests      # offline: parsing, validation, matching rules
S
Description
DNS tools API for zonemaster.es: propagation, resolvers, security tracker, infrastructure, graph, blocklists and DNSBLs
Readme
76 KiB
Languages
Python 98.6%
Shell 1.4%