dns-tools
DNS Tools (SuperTool)
An MXToolbox-style DNS lookup + diagnostics console built into the control plane. One input box runs every common DNS/email/network diagnostic; type a domain, IP, or URL and the tool auto-detects what to run, or pick a command explicitly.
100% ours — pure Node standard library (node:dns, node:net, node:tls), no
third-party packages. Everything runs server-side behind admin auth and the
dns.use permission.
Where it lives
| Layer | Path |
|---|---|
| Page | control-plane/web/app/(god)/dns-tools/page.tsx |
| UI | control-plane/web/components/dns-tools/{super-tool,result-view,command-help}.tsx |
| Server action (auth gate) | control-plane/web/lib/dns/actions.ts |
| Dispatcher / parser | control-plane/web/lib/dns/supertool.ts |
| Toolkit modules | control-plane/web/lib/dns/*.ts |
| Permission | dns.use in lib/rbac.ts |
| Nav | lib/nav.ts → Infrastructure → “DNS Tools” (chord g n) |
Commands
| Command | What it does |
|---|---|
dns | A, AAAA, MX, NS, TXT, SOA, CAA in one shot |
a aaaa cname mx ns txt soa srv caa | Individual record types |
ptr (alias reverse) | Reverse DNS for an IP |
spf | Find + validate SPF (recursive ≤10-lookup rule, all qualifier) |
dmarc | Parse the _dmarc policy |
dkim | selector:domain, or probe ~30 common selectors |
smtp | Connect to the top MX: banner, EHLO caps, STARTTLS (read-only; no relay test) |
blacklist (alias rbl) | Check an IP against ~28 DNSBLs |
whois | Domain (IANA→registry→registrar) or IP (ARIN→RIR) with referral following |
https (alias http) | Status, redirect chain, server + security headers |
cert (alias ssl/tls) | Certificate chain, expiry, SANs, hostname match |
port | TCP connect test to host:port |
ping | TCP-connect latency (not ICMP — labelled as such) |
propagation (alias dnscheck) | Same record across 6 public resolvers |
dnshealth | Delegation, NS reachability, SOA-serial agreement, apex CNAME |
Input accepts a leading keyword (mx example.com, blacklist 1.2.3.4) or a bare
argument that gets classified: URL → https, IP → blacklist, host:port →
port, otherwise → dns.
Design notes
- One result shape. Every tool returns
ToolResult(lib/dns/types.ts): findings (checkswith pass/warn/fail/info severity), zero or more generic tables, optional raw text, timing. The UI (result-view.tsx) renders any command generically. Results must stay plain-serializable (they cross the'use server'boundary). - Resolver choice is deliberate. Single lookups pin to Cloudflare
(
1.1.1.1) and report which resolver answered. DNSBL queries use the system resolver on purpose — Spamhaus & friends refuse queries arriving via large public resolvers;127.255.255.0/24answers are surfaced as control codes, not listings. - Read-only & honest. SMTP does not run an open-relay test. "ping" is a TCP probe, not ICMP. Limits (lookup counts, redirect hops, response bytes) are bounded; the action has a 30 s overall backstop on top of per-tool timeouts.
Extending
Add a tool by writing a lib/dns/<name>.ts that returns a ToolResult, wiring
it into runCommand + the Command union and COMMANDS catalog in types.ts.
The picker, auto-detect, and renderer pick it up automatically.
Telemetry monitors (Layer 2)
Saved watches that run on a schedule, keep history, and raise alerts on
degradation or drift. Each monitor maps to a SuperTool command (or Cloudflare
drift); the runner reduces the ToolResult to a status + a stable signature.
| Piece | Path |
|---|---|
| Types + catalog | lib/dns/monitors/types.ts |
| Store (PG + in-memory) | lib/dns/monitors/store.ts |
| Runner (status/signature/alerts) | lib/dns/monitors/runner.ts |
| Server actions | lib/dns/monitors/actions.ts (perm dns.monitors) |
| Schema | control-plane/db/schema-dns-monitors.sql |
| Scheduler entrypoint | app/api/v1/monitors/run/route.ts |
| UI | components/dns-tools/monitors-panel.tsx |
Monitor types: record (drift), tls_expiry, blacklist (MTA reputation),
propagation, dns_health, whois_expiry, http, cloudflare_drift.
Status & alerting. A run yields pass | warn | fail | error. An event is
raised when the status gets worse (warn→warn, fail→critical), when the
answer drifts (signature changed), or on recovery. Signatures deliberately
exclude volatile data — TTL columns are dropped, rows are sorted (so record
rotation isn't drift), blacklist uses only the listed set (transient
unreachable zones don't flap), and http uses status + security-header presence
(not volatile header values). blacklist/whois_expiry get type-specific status
(listed-count / days-to-expiry) instead of the generic check rollup.
In-app events are the alert of record. External channels (email / Slack /
PagerDuty / webhook) hook into deliver() in the runner once configured; they're
gated per plan by the monitor's alertChannels.
Scheduling
The scheduler is infra-agnostic — any cron hits the endpoint on an interval:
curl -fsS -X POST https://<control-plane>/v1/monitors/run \
-H "Authorization: Bearer $MONITORS_CRON_SECRET"
It runs every due monitor once (bounded concurrency) and returns
{ ran, changed, alerted }. Fail-closed: with MONITORS_CRON_SECRET unset the
endpoint refuses to run. Wire it from a Coolify scheduled task, GitHub Actions
schedule, or any external pinger (every 1–5 min is plenty; per-monitor
intervals do the real pacing).
Cloudflare drift (Layer 3)
lib/dns/cloudflare-drift.ts reads the zone's records via the Cloudflare API
(lib/fleet/dns.ts → listZoneRecords, scoped CLOUDFLARE_DNS_TOKEN) and
compares each DNS-only record's intended content against what a public
resolver observes. Drift = the live answer no longer matches the zone (stale
cache, competing source, or hijack). Proxied (orange-cloud) records resolve to
Cloudflare's edge by design and are reported as proxied, not drift.
Plan gating
lib/billing/entitlements.ts is the single source of truth for what each
LicenseTier unlocks (monitor quota, min interval, monitor types, Cloudflare,
alert channels, white-label reports). The matrix renders in the UI
(components/dns-tools/tier-matrix.tsx); actions.ts enforces it. The god
console operator is treated as top tier; the customer dashboard will pass the
tenant's own tier.
Environment
| Var | Purpose |
|---|---|
DATABASE_URL | Persist monitors/results/events (else in-memory) |
MONITORS_CRON_SECRET | Bearer secret for /v1/monitors/run (required to run) |
CLOUDFLARE_DNS_TOKEN | Cloudflare drift + zone telemetry (scoped Zone:DNS) |