Commit Graph

122 Commits

Author SHA1 Message Date
Razvan Dimescu
eaab406515 simplify: unify route structs, fix prefix collision, lint fixes
- Unify RouteConfig/RouteEntry/RouteResponse into single RouteEntry
- Fix prefix collision: /api no longer matches /apiary (segment boundary check)
- Add path traversal rejection in route API
- Extract MdnsAnnouncement struct (clippy type_complexity)
- cargo fmt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 06:57:57 +02:00
Razvan Dimescu
9992418908 LAN opt-in, mDNS migration, security hardening, path-based routing
- LAN discovery disabled by default (opt-in via [lan] enabled = true)
- Replace custom JSON multicast (239.255.70.78:5390) with standard mDNS
  (_numa._tcp.local on 224.0.0.251:5353) using existing DNS parser
- Instance ID in TXT record for multi-instance self-filtering
- API and proxy bind to 127.0.0.1 by default (0.0.0.0 when LAN enabled)
- Path-based routing: longest prefix match with optional prefix stripping
  via [[services]] routes = [{path, port, strip?}]
- REST API: GET/POST/DELETE /services/{name}/routes
- Dashboard shows route lines per service when configured
- Segment-boundary route matching (prevents /api matching /apiary)
- Route path validation (rejects path traversal)

Closes #11

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 06:56:31 +02:00
Razvan Dimescu
0a43feaf1a Merge pull request #10 from razvandimescu/fix/fast-network-detect
Reduce network change detection to 5s
2026-03-22 21:47:25 +02:00
Razvan Dimescu
1bf11190d5 reduce network change detection to 5s with tiered polling
LAN IP checked every 5s (cheap UDP socket call). Full upstream
re-detection runs every 30s as safety net, or immediately when
LAN IP changes. Reduces worst-case network switch recovery from
30s to 5s.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:36:03 +02:00
Razvan Dimescu
4f8afcd5b2 bump version to 0.3.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.3.1
2026-03-22 11:32:48 +02:00
Razvan Dimescu
71cf0f0fc5 Merge pull request #9 from razvandimescu/fix/upstream-redetect
Fix DNS failure on network change
2026-03-22 11:23:36 +02:00
Razvan Dimescu
2b64e30bf7 show upstream DNS in stats API and dashboard footer
Expose current upstream address in /stats response. Dashboard footer
now shows "Upstream: x.x.x.x:53" — updates live when the network
watcher swaps the upstream.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 11:04:54 +02:00
Razvan Dimescu
4a1c98b02d fix circular reference: detect DHCP DNS when scutil shows loopback
When numa install is active, scutil --dns only returns 127.0.0.1.
Previously fell back to 9.9.9.9 (Quad9) which fails on networks
that block external DNS. Now reads DHCP-provided DNS from
ipconfig getpacket en0/en1 as intermediate fallback before Quad9.

Tested on a network that blocks 8.8.8.8, 9.9.9.9, 1.1.1.1 but
allows ISP DNS (213.154.124.25) — Numa now auto-detects and uses it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 10:24:54 +02:00
Razvan Dimescu
55ea49b003 generalize upstream re-detection into network change watcher
Always detect network changes (LAN IP, upstream, peers) regardless
of upstream config. LAN IP is now tracked in ServerCtx and updated
every 30s — multicast announcements use the current IP instead of
the startup IP. Upstream re-detection still only runs when
auto-detected. Peer flush triggers on any network change.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:38:09 +02:00
Razvan Dimescu
f01b2418cd fix DNS failure on network change with upstream re-detection
Upstream DNS was resolved once at startup and never updated. Switching
Wi-Fi networks made all queries fail until restart.

Now spawns a background task (every 30s) that re-runs system DNS
discovery and swaps the upstream atomically if it changed. Also flushes
stale LAN peers from the old network on change.

Only activates when upstream is auto-detected (not explicitly configured).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:31:49 +02:00
Razvan Dimescu
32bff69113 Merge pull request #8 from razvandimescu/feat/windows-support
Add Windows support (Phase 1)
v0.3.0
2026-03-22 08:38:10 +02:00
Razvan Dimescu
0a39d98861 fix needless return in trust_ca for Windows clippy
On Windows, the not(macos/linux) cfg block is the only path, so
clippy flags the return as needless. Use expression form instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 08:29:28 +02:00
Razvan Dimescu
ca1f51652b fix Windows clippy errors and unreachable code
Gate version detection behind cfg(unix), fix unreachable Ok(()) after
return in trust_ca, use next_back() and is_some_and() per clippy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 08:23:25 +02:00
Razvan Dimescu
a74d9a4bbb add Windows support (Phase 1)
Cross-platform paths: config_dir() uses %APPDATA%, data_dir() uses
%PROGRAMDATA% on Windows. TLS cert directory uses data_dir() instead
of hardcoded /usr/local/var/numa. Windows DNS discovery via ipconfig.
Fixed cfg gates from not(macos) to explicit linux to prevent Linux
code compiling on Windows. Added Windows target to CI and release
workflows with zip packaging.

System integration (numa install/service) not yet supported on Windows
— users run numa.exe manually.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 08:13:53 +02:00
Razvan Dimescu
e564bd887e updated hero image 2026-03-22 08:04:37 +02:00
Razvan Dimescu
8bece0a0cd Merge pull request #7 from razvandimescu/feat/lan-discovery
Add LAN service discovery via UDP multicast
2026-03-22 08:03:32 +02:00
Razvan Dimescu
990c865f41 update demo script for new dashboard layout and LAN badges
Reorder scenes to show services first (matching panel order),
scroll to blocking panel for domain check scene. LAN badge
now visible after adding a service.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 07:04:06 +02:00
Razvan Dimescu
0ba2d3c72d update README, dashboard layout, and version bump to 0.3.0
Add LAN discovery section to README with mesh and hub mode docs.
Update comparison table and roadmap. Move Local Services panel
above Blocking in dashboard for developer-first layout.
Bump version from 0.1.0 to 0.3.0 to match release cadence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 06:59:47 +02:00
Razvan Dimescu
def89ffe59 add LAN accessibility indicator for services
Show whether each service is reachable from the network or bound to
localhost only. Dashboard displays green "LAN" or amber "local only"
badge next to each healthy service. Unified TCP check function,
concurrent health+LAN probes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 06:35:12 +02:00
Razvan Dimescu
a29e4aeb96 fix LAN discovery: instance-based self-filter and multicast port reuse
Replace IP-based self-announcement filtering with a per-process instance
ID (pid ^ timestamp) so multiple instances on the same host can discover
each other. Enable SO_REUSEPORT for multicast socket binding on Unix.
Add multicast address validation on configured group.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 00:20:33 +02:00
Razvan Dimescu
d355f8d005 fix rustfmt formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:54:03 +02:00
Razvan Dimescu
c410945222 add LAN service discovery via UDP multicast
Numa instances on the same network auto-discover each other's .numa
services. No config, no cloud — just multicast on 239.255.70.78:5390.

- PeerStore with lazy expiry (90s timeout, 30s broadcast interval)
- DNS resolves remote .numa services to peer's LAN IP (not localhost)
- Proxy forwards to peer IP for remote services
- Graceful degradation if multicast bind fails

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:45:46 +02:00
Razvan Dimescu
b3f3a4f36c fix aarch64 musl build: use cross instead of musl.cc download
musl.cc was unreachable from CI. cross handles the Docker-based
cross-compilation automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v0.2.1
2026-03-21 13:01:59 +02:00
Razvan Dimescu
14b035387b switch Linux builds to musl for static binaries
glibc-linked binaries fail on older distros (GLIBC_2.38 not found).
musl produces fully static binaries that work on any Linux.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:50:34 +02:00
Razvan Dimescu
d457ffc296 remove unused rustls-pemfile dependency
Dead code — certs are generated at startup, not loaded from PEM files.
Removes RUSTSEC-2025-0134 warning. Audit now passes clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:03:13 +02:00
Razvan Dimescu
8ab50844c2 fix audit: update rustls-webpki, ignore unmaintained pemfile warning
RUSTSEC-2026-0049 fixed by updating rustls-webpki 0.103.9 → 0.103.10.
RUSTSEC-2025-0134 (rustls-pemfile unmaintained) ignored — no replacement
available, warning only, not a vulnerability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 11:59:52 +02:00
Razvan Dimescu
e04afe5b70 add cargo-audit to Makefile lint target
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:53:09 +02:00
Razvan Dimescu
44113492f0 add CI/crates.io/license badges, cargo-audit in CI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:51:13 +02:00
Razvan Dimescu
ec41f32d4e clarify single binary — no PHP, no web server, no database
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 10:17:39 +02:00
Razvan Dimescu
a35b0ea23c updated hero 2026-03-21 04:49:18 +02:00
Razvan Dimescu
fbdb0a245f Merge pull request #6 from razvandimescu/feat/404-page
Styled 404 page for unregistered .numa domains
2026-03-21 04:33:59 +02:00
Razvan Dimescu
285778b646 add styled 404 page for unregistered .numa domains
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>
2026-03-21 04:31:17 +02:00
Razvan Dimescu
792f745587 remove docs from repo, add codesign to install.sh
Docs contain internal planning (token economics, growth plan) that
should not be public. Keep locally via .gitignore.
Added macOS ad-hoc codesign step to install.sh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v0.2.0
2026-03-21 04:13:21 +02:00
Razvan Dimescu
1ad4e127ef Merge pull request #5 from razvandimescu/feat/network-economics
Launch hardening: TC bit, Dockerfile, deploy, truncation fix
2026-03-21 03:51:17 +02:00
Razvan Dimescu
5c1f2e013a restructure README for Show HN, add post draft
Moved "from scratch in Rust" into hero, added AdGuard Home to
comparison, named Hagezi Pro blocklist, cut 40% (API table + config
to docs), install script first in Quick Start, added Linux mention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 03:51:04 +02:00
Razvan Dimescu
7a64e7c4aa fix truncation check: use == instead of >= for buffer-full detection
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>
2026-03-21 03:35:21 +02:00
Razvan Dimescu
2cb87bbe83 fix rustfmt formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 03:31:44 +02:00
Razvan Dimescu
4b60a4b49c launch hardening: TC bit, Dockerfile, platform-aware deploy
- 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>
2026-03-21 03:31:15 +02:00
Razvan Dimescu
c803bb2b41 Merge pull request #4 from razvandimescu/feat/network-economics
Add hero GIF, network economics doc, updated roadmap
2026-03-21 03:09:57 +02:00
Razvan Dimescu
66f8bfbac2 add hero GIF to README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 03:06:11 +02:00
Razvan Dimescu
4e1eafb34a update roadmap, add network economics doc, remove CLAUDE.md from repo
- Expanded roadmap: pkarr → global .numa names → audit protocol →
  proof-of-service chain → .onion bridge
- Added docs/numa-network-economics.md: token model, proof-of-service,
  chain design, competitive analysis vs Namecoin/ENS/Handshake
- Removed CLAUDE.md from repo (stays in .gitignore, local only)
- Unignored docs/ directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 03:02:26 +02:00
Razvan Dimescu
e65f5a36fc Merge pull request #3 from razvandimescu/feat/async-tokio
Async architecture, local service proxy, TLS, blocking panel
2026-03-21 01:38:29 +02:00
Razvan Dimescu
cfd9a562af fix CA removal: delete by SHA-1 hash, update README with TLS
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>
2026-03-21 01:35:14 +02:00
Razvan Dimescu
5e7a653f9c fix rustfmt formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 01:15:51 +02:00
Razvan Dimescu
3bfcd827ac add TLS, service persistence, blocking panel, query types
- Local TLS: auto-generated CA + per-service certs (explicit SANs, not
  wildcards — browsers reject *.numa under single-label TLDs). HTTPS
  proxy on :443 via rustls/tokio-rustls. `numa install` trusts CA in
  macOS Keychain / Linux ca-certificates.
- Service persistence: user-added services saved to
  ~/.config/numa/services.json, survive restarts.
- Blocking panel: renamed "Check Domain" to "Blocking" with sources
  display, allowlist management UI, unpause button.
- Query types: recognize SOA, PTR, TXT, SRV, HTTPS (type 65) instead
  of logging as UNKNOWN.
- Blocklist gzip: reqwest now decompresses gzip responses from CDNs.
- Unified config_dir() in lib.rs for consistent path resolution under
  sudo and launchd. TLS certs use /usr/local/var/numa/ (writable as
  root daemon).
- Dashboard UX: panel subtitles differentiating overrides vs services,
  better placeholders, proxy route display, 600px query log height.
- Deploy: make deploy handles build+copy+codesign+restart cycle.
- Demo: scripts/record-demo.sh for recording hero GIF with CDP.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 01:15:07 +02:00
Razvan Dimescu
10502f2db2 fix service restart: add codesign and make deploy target
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>
2026-03-20 15:22:33 +02:00
Razvan Dimescu
754b064570 fix rustfmt formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 15:07:42 +02:00
Razvan Dimescu
8f959ce0a5 add local service proxy with .numa domains
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>
2026-03-20 15:07:15 +02:00
Razvan Dimescu
14a9e9e7e3 add numa service restart command
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>
2026-03-20 14:26:56 +02:00
Razvan Dimescu
48657aec6c update CLAUDE.md and development plan with current state
Reflects: EDNS fix, 4096 buffer, system DNS auto-detect, service
management, domain check, query log filtering, install script,
launchctl bootstrap note, Rust 2021 edition, 19 endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 14:23:56 +02:00