diff --git a/README.md b/README.md index a72a070..fcda4e2 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ manages (it removes them; its block supersedes them). | `bin/wg-dns-sync` | **apricot** | Renders `mesh-hosts.json` → `/etc/dnsmasq.d/wg-mesh.conf` (host `.wg` + `.lan` records on `10.9.0.2:53`, for wg clients with `DNS=10.9.0.2`). Idempotent; `--dry-run`. | | `bin/mesh-hosts-render` | **every host** | Renders the fleet `/etc/hosts` block (bare/`.lan` at current IPs, `.wg`, service vhosts) and splices it at the top of `/etc/hosts`, adopting any loose lines it supersedes. Idempotent. `--print`/`--diff`/`--install`. | | `bin/forge-dns-render` | **laptop/dev machines** | DX-only: renders cloud Forgejo shortcuts (mcforge, ctforge, ...) from `~/.vault/*_forge_creds` into a managed block at the bottom of `/etc/hosts`. Used by `net sync` and per-project `./run forge:dns`. Adopts loose entries. `--print`/`--diff`/`--install`. | +| dx config in mesh-hosts.json | data-driven | `"dx": { "hide_homelan": true }` hides homelan hosts (apricot/pear/fennel + LAN names/services) from all generated /etc/hosts + ssh fleet blocks (only cloud/DO remain). Full data preserved for recovery (set false + `net sync`). Used while DO-only. | | `smart-lan-router/` | **fennel** | `com.lilith.smart-lan-router.plist` (launchd) + `install-agent.sh` (one installer: launchd or systemd) + `smart-lan-router.service.tmpl`. | | [`tray/`](tray/) | **fennel** (menu bar) | The fleet tray (absorbed from the old `wireguard-vpn-tray` repo). Icon = tunnel state (green/yellow/red); menu = live fleet view from `data/agent-status.json`: agent freshness, HOME/AWAY + route, discovered host IPs, repo HEAD. Connect/disconnect actions. Install: `bash tray/install-tray.sh` (as the user, no sudo). | @@ -129,7 +130,7 @@ its own code changes — fleet updates propagate by pushing to the forge. | add/rename a host, change a MAC, add a service vhost or phone | edit [`data/mesh-hosts.json`](data/mesh-hosts.json), let autocommit push — **every agent pulls, restarts on code change, and converges (incl. its OS hostname) within minutes** | | react to a host changing DHCP IP | nothing — agents discover it by MAC and regenerate `/etc/hosts` + ssh automatically | | rename a node's OS hostname | nothing by hand — `fleet.enforce_hostname` makes the node's own agent do it | -| force a regen now | `net sync` (mesh-hosts + forge-dns + ssh) or the individual `sudo ... --install` | +| force a regen now | `net sync` (mesh-hosts + forge-dns + ssh) or the individual `sudo ... --install`. Toggle dx.hide_homelan in data/mesh-hosts.json then sync to hide/show homelan. | | apricot mesh DNS (phones) | `sudo wg-dns-sync` on apricot | | enroll a phone | `wg-phone-add -d ` then add a `class: phone` entry | diff --git a/bin/host-apply b/bin/host-apply index fecd138..9cfea12 100755 --- a/bin/host-apply +++ b/bin/host-apply @@ -60,6 +60,8 @@ data_file="$root/data/mesh-hosts.json" [ -f "$data_file" ] || { echo "host-apply: cannot locate data/mesh-hosts.json" >&2; exit 1; } command -v jq >/dev/null || { echo "host-apply: jq not installed" >&2; exit 1; } +hide_homelan=$(jq -r '.dx.hide_homelan // false' "$data_file") + # Overlay: current LAN IPs discovered by the daemon (data/lan-state.json, a # {name: ip} map) override the static `lan` seed, so ssh tracks DHCP drift. overlay='{}' @@ -105,12 +107,17 @@ reachlan=$(jq -r --arg s "$self" ' # --- render this device's ssh block -------------------------------------------- render_block() { printf '%s\n' "$BEGIN" - printf '# rendered for: %s (vantage: %s)\n' "$self" \ - "$( [ "$reachlan" = "true" ] && echo 'LAN-capable → prefer .lan' || echo 'mesh-only → prefer .wg' )" - jq -r --arg s "$self" --argjson reachlan "$reachlan" --argjson ov "$overlay" ' + if [ "$hide_homelan" = "true" ]; then + printf '# rendered for: %s (dx/cloud-only; homelan hidden — set dx.hide_homelan=false to recover)\n' "$self" + else + printf '# rendered for: %s (vantage: %s)\n' "$self" \ + "$( [ "$reachlan" = "true" ] && echo 'LAN-capable → prefer .lan' || echo 'mesh-only → prefer .wg' )" + fi + jq -r --arg s "$self" --argjson reachlan "$reachlan" --argjson ov "$overlay" --argjson hide "$hide_homelan" ' .hosts[] | select(.name != $s) | select(.ssh_user != null) + | select( if $hide then (.class == "cloud") else true end ) | . as $h | (($ov[$h.name]) // $h.lan) as $lan | ( $h.public diff --git a/bin/mesh-hosts-render b/bin/mesh-hosts-render index ece0fc2..19da155 100755 --- a/bin/mesh-hosts-render +++ b/bin/mesh-hosts-render @@ -71,6 +71,8 @@ data_file="$root/data/mesh-hosts.json" command -v jq >/dev/null || { echo "mesh-hosts-render: jq not installed" >&2; exit 1; } jq empty "$data_file" || { echo "mesh-hosts-render: invalid JSON in $data_file" >&2; exit 1; } +hide_homelan=$(jq -r '.dx.hide_homelan // false' "$data_file") + # Overlay: current LAN IPs discovered by the daemon (data/lan-state.json, a # {name: ip} map) override the static `lan` seed, so records track DHCP drift. overlay='{}' @@ -101,10 +103,14 @@ render_block() { printf '%s\n' "$BEGIN" printf '# Auto-generated from net-tools/data/mesh-hosts.json + lan-state.json — re-run to update.\n' printf '# bare/.lan = current LAN IP (direct at home, tunnel when away) · .wg = mesh IP\n' + if [ "$hide_homelan" = "true" ]; then + printf '# dx mode: homelan hidden (only cloud/DO hosts rendered). Data preserved for recovery.\n' + fi # LAN records — current discovered IP (overlay) over the static seed. Bare # names live here only when THIS node can reach LAN IPs (vantage). - jq -r --argjson ov "$overlay" --argjson reachlan "$reachlan" ' + jq -r --argjson ov "$overlay" --argjson reachlan "$reachlan" --argjson hide "$hide_homelan" ' .hosts[] + | select( if $hide then (.class == "cloud") else true end ) | . as $h | (($ov[$h.name]) // $h.lan) as $lan | select($lan != null) @@ -114,8 +120,9 @@ render_block() { ' "$data_file" # Mesh (.wg) records — explicit tunnel path. Bare names land here for # LAN-less hosts always, and for ALL hosts when this node is mesh-only. - jq -r --argjson reachlan "$reachlan" ' + jq -r --argjson reachlan "$reachlan" --argjson hide "$hide_homelan" ' .hosts[] + | select( if $hide then (.class == "cloud") else true end ) | . as $h | "\($h.wg)\t" + ((([$h.name] + ($h.aliases // [])) | map(. + ".wg")) | join(" ")) @@ -124,12 +131,12 @@ render_block() { ' "$data_file" # Service vhosts — the hosting host'\''s current LAN IP, or its wg IP from a # mesh-only vantage. - jq -r --argjson ov "$overlay" --argjson reachlan "$reachlan" ' + jq -r --argjson ov "$overlay" --argjson reachlan "$reachlan" --argjson hide "$hide_homelan" ' . as $d | ($d.services // {}) | to_entries[] | select(.key != "_note") | .key as $hname - | ($d.hosts[] | select(.name == $hname)) as $h + | ($d.hosts[] | select(.name == $hname) | select( if $hide then (.class == "cloud") else true end )) as $h | (if $reachlan then (($ov[$hname]) // $h.lan) else $h.wg end) as $addr | select($addr != null) | "\($addr)\t\(.value | join(" "))" diff --git a/data/mesh-hosts.json b/data/mesh-hosts.json index b00ac78..79bcebd 100644 --- a/data/mesh-hosts.json +++ b/data/mesh-hosts.json @@ -33,6 +33,10 @@ "gateway_mac": "c4:4f:d5:5a:61:6f", "gateway_note": "Xfinity broadband gateway. gateway_mac is the home-LAN fingerprint: the smart-lan-router daemon treats the laptop as 'home' only when the default gateway on the LAN interface has this MAC — distinguishes the real home LAN from any visited 10.0.0.0/24 network. DHCP reservations only via xFi/web UI, no scriptable API." }, + "dx": { + "hide_homelan": true, + "_note": "When true, renderers (mesh-hosts-render, host-apply) omit homelan hosts (apricot/pear/fennel + their LAN/.lan/bare names and services on them) from generated /etc/hosts and ~/.ssh/config. Only cloud/DO hosts (yuzu, lime + their public/WG) and dx-forges (separate) are shown. Full homelan data preserved in 'hosts'/'lan'/'services' for easy recovery — set false and re-render (net sync). We are currently DO-only for DX." + }, "hosts": [ { "name": "apricot",