diff --git a/.gitignore b/.gitignore index 1b715be..cfa6940 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target CLAUDE.md -docs/ diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 9d0fd47..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,113 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Overview - -**Numa** — a portable DNS resolver with ad blocking, developer overrides, and a live dashboard. Built from scratch in Rust. Named after Numa Pompilius, the Roman king who established lasting institutions. - -Today: DNS forwarding/caching proxy with ad blocking, ephemeral overrides, live dashboard, and system DNS integration. -Next: Self-sovereign DNS via pkarr/Mainline DHT. -Vision: Incentivized resolver network with staking, challenge-based auditing, and token economics. - -## Build & Run - -```bash -cargo build # compile -sudo cargo run # run with default config (numa.toml) -sudo cargo run -- path/to/config # run with custom config path -RUST_LOG=debug sudo cargo run # verbose logging -make lint # clippy + rustfmt check -``` - -Test with: `dig @127.0.0.1 google.com` - -CLI commands: -```bash -numa help # show all commands -numa install # set system DNS to 127.0.0.1 -numa uninstall # restore original DNS -numa service start # install as persistent service (launchd/systemd) -numa service stop # uninstall service + restore DNS -numa service status # check service status -``` - -Dashboard: http://numa.numa (or http://localhost:5380) - -## Architecture - -``` -UDP :53 ──▶ handle_query() - │ - ├─ 1. Override Store (ephemeral, auto-expiry) - ├─ 2. .numa TLD (local service domains → 127.0.0.1) - ├─ 3. Blocklist (385K+ domains, subdomain matching) - ├─ 4. Local Zones (TOML config) - ├─ 5. Cache (TTL-aware, lazy eviction) - └─ 6. Upstream Forward (auto-detected from OS, conditional forwarding) - -HTTP :80 ──▶ Reverse proxy for .numa domains (WebSocket support) -HTTPS :443 ──▶ TLS reverse proxy (auto-generated local CA + wildcard *.numa cert) -HTTP :5380 ──▶ Axum REST API (22+ endpoints) + Dashboard -``` - -### Source Files - -``` -src/ - main.rs # startup: load config, bind UDP, spawn API + proxy, blocklist download, per-query task loop - lib.rs # module declarations, Error/Result type aliases - ctx.rs # ServerCtx shared state + handle_query() pipeline - api.rs # Axum REST server (22 endpoints, port 5380) + embedded dashboard - config.rs # TOML config loading with defaults (server, upstream, cache, blocking, proxy, zones) - proxy.rs # HTTP/HTTPS reverse proxy for .numa domains (port 80 + 443, WebSocket upgrade) - tls.rs # Local CA + wildcard cert generation (rcgen), rustls ServerConfig builder - service_store.rs # ServiceStore — name-to-port mappings, persisted to ~/.config/numa/services.json - blocklist.rs # BlocklistStore — HashSet, download, parse, subdomain matching, check - override_store.rs # OverrideStore — ephemeral domain overrides with auto-expiry - query_log.rs # ring buffer (VecDeque, 1000 entries) for recent queries - cache.rs # DnsCache — TTL-aware, lazy eviction every 1000 lookups - forward.rs # async UDP forwarding to upstream resolver - stats.rs # ServerStats counters + QueryPath enum (6 categories) - system_dns.rs # OS DNS discovery (scutil/resolv.conf), install/uninstall, service management - buffer.rs # BytePacketBuffer — 4096-byte DNS wire format I/O - header.rs # DnsHeader — 12-byte bitfield parsing/serialization - question.rs # DnsQuestion + QueryType enum (A, NS, CNAME, SOA, PTR, MX, TXT, AAAA, SRV, HTTPS) - record.rs # DnsRecord enum — wire format read/write per record type (filters UNKNOWN on write) - packet.rs # DnsPacket — header + questions + answers + authorities + resources -site/ - dashboard.html # live dashboard (embedded at compile time via include_str!) - index.html # landing page (Roman Stone theme) -``` - -## Config - -`numa.toml` at project root. Sections: `[server]`, `[upstream]`, `[cache]`, `[blocking]`, `[proxy]`, `[[services]]`, `[[zones]]`. Falls back to sensible defaults if file is missing. Upstream auto-detected from system resolver if not set. - -## REST API - -Dashboard: GET `/` (embedded HTML) -Override management: POST/GET/DELETE `/overrides`, POST `/overrides/environment` -Services: GET/POST `/services`, DELETE `/services/{name}` -Blocking: GET `/blocking/stats`, PUT `/blocking/toggle`, POST `/blocking/pause`, POST `/blocking/unpause`, GET/POST `/blocking/allowlist`, GET `/blocking/check/{domain}` -Diagnostics: GET `/diagnose/{domain}`, `/query-log`, `/stats`, `/cache`, `/health` -Cache: DELETE `/cache`, `/cache/{domain}` - -## Key Details - -- Rust 2021 edition, async via `tokio` (rt-multi-thread) -- Deps: tokio, axum, hyper, hyper-util, serde, serde_json, toml, log, env_logger, reqwest, futures, rcgen, rustls, tokio-rustls, time (zero DNS libraries) -- Shared config dir: `~/.config/numa/` via `config_dir()` in `lib.rs` (handles sudo correctly) -- TLS: auto-generated local CA + wildcard `*.numa` cert at `~/.config/numa/`. `numa install` trusts CA in OS keychain. -- Service persistence: user-added services saved to `~/.config/numa/services.json`, survives restarts -- Deploy workflow: `make deploy` (build release → copy → codesign → kill → launchd respawns) -- DNS buffer size: 4096 bytes (EDNS-compatible). UNKNOWN record types (e.g. OPT) filtered on serialization. -- `BytePacketBuffer::read_qname` handles label compression (pointer jumps) -- `type Error = Box` / `type Result` aliased in `lib.rs` -- Shared state via `Arc` with `std::sync::Mutex` (sub-microsecond holds, never across `.await`) -- Cache: TTL clamped between `min_ttl` and `max_ttl`, lazy eviction every 1000 queries -- Blocklist: parsed outside lock, swapped atomically. `is_blocked()` takes `&self` (read-only). -- Upstream: auto-detected from `scutil --dns` (macOS) or `/etc/resolv.conf` (Linux). Falls back to Quad9. -- Conditional forwarding: Tailscale/VPN domains auto-routed to correct upstream. -- macOS service: launchd plist with KeepAlive + RunAtLoad. Use `launchctl bootstrap/bootout` (not load/unload). -- Logging controlled via `RUST_LOG` env var. Default: `info` diff --git a/README.md b/README.md index aa44da2..8277690 100644 --- a/README.md +++ b/README.md @@ -228,8 +228,11 @@ Zero external DNS libraries. RFC 1035 wire protocol parsed by hand. Dependencies - [x] System DNS auto-discovery — Tailscale, VPN split-DNS - [x] System DNS auto-configuration — `numa install` / `numa uninstall` - [x] Local service proxy — `.numa` domains with HTTP/HTTPS reverse proxy, auto TLS, WebSocket -- [ ] pkarr integration — self-sovereign DNS via Mainline DHT -- [ ] Decentralized resolver network — staking, auditing, token economics +- [ ] pkarr integration — resolve Ed25519 keys via Mainline DHT (15M nodes) +- [ ] Global `.numa` names — self-publish, DHT-backed, first-come-first-served +- [ ] Audit protocol — challenge-based verification of resolver honesty +- [ ] Numa Network — proof-of-service consensus, NUMA token, paid `.numa` domains +- [ ] `.onion` bridge — human-readable `.numa` names for Tor hidden services ## License diff --git a/site/index.html b/site/index.html index 3fcab04..7982daf 100644 --- a/site/index.html +++ b/site/index.html @@ -1357,27 +1357,27 @@ footer .closing {
Phase 4 - Local service proxy — .numa domains, HTTP reverse proxy, WebSocket support + Local service proxy — .numa domains, HTTP/HTTPS reverse proxy, auto TLS, WebSocket
Phase 5 - pkarr spike — DHT resolution and publish endpoint + pkarr integration — resolve Ed25519 keys via Mainline DHT (15M nodes)
Phase 6 - pkarr product — human-readable aliases, re-publish daemon, key management + Global .numa names — self-publish, DHT-backed, first-come-first-served
Phase 7 - Challenge and audit protocol for verifiable resolver behavior + Audit protocol — challenge-based verification of resolver honesty
Phase 8 - Token economics, staking, and slashing mechanism + Numa Network — proof-of-service consensus, NUMA token, paid .numa domains
Phase 9 - Decentralized resolver marketplace + .onion bridge — human-readable .numa names for Tor hidden services