Roman Stone themed 404 with Instrument Serif heading, JetBrains Mono
domain badge, brick pattern background, syntax-highlighted curl
example, and a delayed easter egg. Also updates dashboard link in
README to numa.numa.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
recv_from can never return more bytes than the buffer size — the kernel
truncates silently. == is the correct heuristic for detecting truncation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Set TC (truncation) bit when response exceeds 4096-byte buffer
instead of dropping the response silently. Clients can retry via TCP.
- Log when upstream response is truncated in forward.rs.
- Dockerfile: bump to Rust 1.88, include site/service files, use
alpine runtime instead of scratch, add cmake/perl for aws-lc-sys.
- Makefile deploy: platform-aware — codesign on macOS, systemctl on Linux.
- README: trim roadmap to near-term items only.
- Verified: Docker build + smoke test passes on Linux (Alpine musl).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
security delete-certificate -c fails when multiple certs match.
Now finds all certs by hash and deletes each individually.
Also updated README with HTTPS, service persistence, and TLS mentions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
macOS kills unsigned binaries, so numa service restart failed after
copying a new build. Added ad-hoc codesign to restart flow and a
make deploy target that handles the full build-copy-sign-restart cycle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HTTP reverse proxy on port 80 lets developers use clean domain names
(frontend.numa, api.numa) instead of localhost:PORT. Includes WebSocket
upgrade support for HMR, TCP health checks, dashboard UI panel, and
REST API for service management. numa.numa is preconfigured for the
dashboard itself.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Kills the running process and lets launchd/systemd respawn it
with the updated binary. DNS stays configured throughout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default upstream auto-detected from system resolver (scutil/resolv.conf)
instead of hardcoding Google 8.8.8.8. Falls back to Quad9 (9.9.9.9).
- Single scutil --dns pass for both upstream detection and forwarding rules
- Linux: reads backup resolv.conf if current only has loopback
- Service start/stop now couples DNS config (install on start, uninstall on stop)
- Install script for one-line binary install from GitHub Releases
- GitHub Actions release workflow: builds for macOS/Linux x86_64/aarch64
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: upstream resolvers return EDNS OPT records (type 41) in
the additional section. Our parser reads them as UNKNOWN, but write()
silently skips them — creating a header that claims N additional records
but a body with 0, producing FORMERR on the client side.
Fix: filter out UNKNOWN records before serialization and adjust header
counts to match. Also increase BytePacketBuffer from 512 to 4096 bytes
to handle modern DNS responses with many records.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GET /blocking/check/{domain} — returns whether a domain is blocked,
the reason (exact match, parent domain, allowlist, disabled), and
the matching rule. Dashboard sidebar has a "Check Domain" search
box with inline results and one-click allow button.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- numa service start/stop/status commands (launchd + systemd)
- Dashboard footer shows log paths (macOS + Linux) and GitHub link
- Help text updated with all service commands
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Detect systemd-resolved: use drop-in config instead of overwriting
/etc/resolv.conf (which gets regenerated)
- Warn if /etc/resolv.conf is a symlink (NetworkManager, etc.)
- Fix TOCTOU: attempt copy/remove directly, handle NotFound
- Remove side-effect from backup_path_linux (no eager mkdir)
- Fix macOS $HOME fallback: /var/root instead of /tmp
- Log warnings on launchctl/systemctl failures instead of silencing
- Delete plist before unloading (prevents zombie restarts)
- Extract ensure_binary_installed helper on Linux
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Linux:
- numa install: backs up /etc/resolv.conf, sets nameserver to 127.0.0.1
- numa uninstall: restores original /etc/resolv.conf from backup
- numa service start: installs systemd unit, enables + starts
- numa service stop: stops, disables, removes unit file
- numa service status: shows systemctl status
macOS: launchd plist (already working)
Both platforms: Restart=always / KeepAlive=true for crash recovery.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move HashMap, PathBuf, numa_data_dir, backup_path inside macOS
cfg blocks so Linux builds don't see unused imports/functions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
numa install — saves current DNS, sets all network services to 127.0.0.1
numa uninstall — restores original DNS from ~/.numa/original-dns.json
numa help — shows usage
macOS: uses networksetup to enumerate services and set/restore DNS.
Linux: stubs with instructions for manual setup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- DNS-level ad blocking: 385K+ domains via Hagezi Pro blocklist, subdomain
matching, one-click allowlist, pause/toggle, background refresh every 24h
- Live dashboard at :5380 with real-time stats, query log, override
management (create/edit/delete), blocking controls
- System DNS auto-discovery: parses scutil --dns on macOS to find
conditional forwarding rules (Tailscale, VPN split-DNS)
- REST API expanded to 18 endpoints (blocking, overrides, diagnostics)
- Startup banner with colored system info
- Performance benchmarks (bench/dns-bench.sh)
- Landing page updated with new positioning and comparison table
- CI, Dockerfile, LICENSE, development plan docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>