Add mDNS / .local discovery to live USB pre-build plan (Claude)
Third access path for the live USB, sitting below Tailscale MagicDNS but
above the bare DHCP-IP fallback:
ssh clawdie@clawdie-live (Tailscale MagicDNS — preferred)
ssh clawdie@clawdie-live.local (mDNS / Avahi — always-on LAN)
ssh clawdie@<dhcp-ip> (last-resort fallback)
The implementation cost is small because Avahi is already in the live
dependency closure. The packaged ssh.service file advertises _ssh._tcp
on port 22, so no Avahi config edits are needed — we just enable the
daemon, add nss_mdns for outbound .local resolution, and patch
nsswitch.conf.
Doc changes (no code yet, implementation lands on the next build):
- BUILD.md gets a "LAN discovery (mDNS / Avahi)" subsection alongside
the SSH key note, with the three-path priority order, the
implementation contract, the scope-discipline reminder that
Clawdie internal services stay on home.arpa (not .local), and the
multicast-hostile-network caveat.
- doc/LIVE-SESSION-REVIEW.md gets a parallel "Pre-build plan: mDNS /
.local discovery for the live USB" section with the requirements
table (matching the format used for the SSH plan), the concrete
package/rc.conf/nsswitch contract, and Level-1 static-check hooks
for TESTING.md to consume once code lands.
Scope discipline carried explicitly in both docs:
home.arpa = Clawdie internal DNS (ai/cms/git/<tenant>)
.local = mDNS LAN discovery for the live USB only
RFC 6762 reserves .local for mDNS; mixing it with internal service
names breaks both. The next-build implementation must not move internal
services to .local.
Package choice fixed:
avahi-app (already transitive; list explicitly to pin contract)
nss_mdns (small, not currently in closure)
Not mDNSResponder — less stack churn and avahi already ships the
ssh.service advertisement we want.
Build: pass — sh -n build.sh
Tests: pass — git diff --check
This commit is contained in:
parent
2b13e11bc9
commit
c66d060867
2 changed files with 130 additions and 0 deletions
43
BUILD.md
43
BUILD.md
|
|
@ -186,6 +186,49 @@ themselves after first boot or build their own image. The dedicated
|
|||
See `doc/LIVE-SESSION-REVIEW.md` for the full pre-build plan and TESTING
|
||||
hooks.
|
||||
|
||||
### LAN discovery (mDNS / Avahi)
|
||||
|
||||
The live USB advertises itself on the local network as
|
||||
`clawdie-live.local` so the operator can SSH/`scp` without finding the
|
||||
DHCP-assigned IP each boot. Two access paths in priority order:
|
||||
|
||||
```sh
|
||||
# Preferred when Tailscale was passed at build time:
|
||||
ssh clawdie@clawdie-live # MagicDNS
|
||||
|
||||
# Always-on LAN discovery — no Tailscale required:
|
||||
ssh clawdie@clawdie-live.local # mDNS / Avahi
|
||||
|
||||
# Last-resort fallback if multicast is blocked on the network:
|
||||
ssh clawdie@<dhcp-ip-from-router>
|
||||
```
|
||||
|
||||
The implementation contract:
|
||||
|
||||
- Explicit packages in `packages/pkg-list-live-operator.txt`:
|
||||
`avahi-app` (already transitive in the closure, list explicitly to
|
||||
pin the contract) and `nss_mdns`.
|
||||
- `avahi_daemon_enable="YES"` in live rc.conf. `dbus_enable="YES"` is
|
||||
already set; Avahi depends on it.
|
||||
- `/etc/nsswitch.conf` `hosts:` line set to
|
||||
`files mdns_minimal [NOTFOUND=return] dns mdns` so `.local` names
|
||||
resolve from the live USB itself.
|
||||
- No config changes to the packaged Avahi `ssh.service` — its
|
||||
`_ssh._tcp` advertisement is what we want.
|
||||
|
||||
**Scope discipline:** mDNS is **only** for LAN discovery of the live
|
||||
USB itself. Clawdie's internal service names continue to live under
|
||||
`home.arpa` (`ai.home.arpa`, `cms.home.arpa`, `git.home.arpa`,
|
||||
`<tenant>.home.arpa`). Do not switch internal services to `.local` —
|
||||
RFC 6762 reserves `.local` for mDNS, and mixing the two namespaces
|
||||
breaks both.
|
||||
|
||||
**Network caveat:** some corporate networks, hotel Wi-Fi, and isolated
|
||||
guest VLANs block multicast traffic. In those environments
|
||||
`clawdie-live.local` won't resolve and the operator falls back to the
|
||||
Tailscale path (if configured) or the DHCP IP path. Worth knowing
|
||||
before debugging "mDNS doesn't work" on a hostile network.
|
||||
|
||||
---
|
||||
|
||||
## Build Output and Provenance
|
||||
|
|
|
|||
|
|
@ -521,6 +521,93 @@ their hardware. For **dev/test images** that's the right tradeoff. For
|
|||
their own image with their own key. The dedicated `clawdie-live-usb` key
|
||||
suggestion above keeps personal keys off shareable images.
|
||||
|
||||
### Pre-build plan: mDNS / `.local` discovery for the live USB
|
||||
|
||||
The SSH plan above gives the operator three access paths (Tailscale,
|
||||
LAN-via-DHCP-IP, and TTY). The DHCP-IP path requires knowing the IP. mDNS
|
||||
fixes that for any LAN that allows multicast: the live USB advertises itself
|
||||
as `clawdie-live.local` and the operator's laptop resolves the name without
|
||||
DHCP-server inspection.
|
||||
|
||||
#### Why mDNS — and what it is *not*
|
||||
|
||||
- **mDNS is LAN discovery for the live USB itself.** It is **not** Clawdie's
|
||||
internal DNS namespace. Internal service names stay under `home.arpa`:
|
||||
`ai.home.arpa`, `cms.home.arpa`, `git.home.arpa`, `<tenant>.home.arpa`.
|
||||
- RFC 6762 reserves the `.local` TLD for mDNS. Mixing internal services
|
||||
into `.local` breaks both namespaces — don't do it.
|
||||
- mDNS sits **below** Tailscale's MagicDNS in the priority order. The
|
||||
tailnet path is preferred when configured because it works across NAT
|
||||
and uses unicast; mDNS is the always-on fallback when Tailscale is
|
||||
absent or down.
|
||||
|
||||
#### Implementation requirements before build
|
||||
|
||||
| Requirement | Implementation |
|
||||
|---|---|
|
||||
| Advertise live USB on LAN | `avahi_daemon_enable="YES"` in live rc.conf |
|
||||
| Stable mDNS name | hostname is already `clawdie-live`, so the advertised name becomes `clawdie-live.local` automatically |
|
||||
| Advertise SSH service | use the packaged Avahi `ssh.service` (`_ssh._tcp` on port 22) — no config changes needed |
|
||||
| Resolve `.local` names *from* the USB | add `nss_mdns` and patch `/etc/nsswitch.conf` `hosts:` line |
|
||||
| Keep Clawdie internal names sane | continue using `home.arpa`; do not move internal services to `.local` |
|
||||
|
||||
#### Concrete contract
|
||||
|
||||
- **Packages.** Add explicitly to `packages/pkg-list-live-operator.txt`:
|
||||
- `avahi-app` — already transitive in the live closure, but list
|
||||
explicitly so the contract is pinned (matches the pattern used for
|
||||
`wifi-firmware-kmod`).
|
||||
- `nss_mdns` — not currently included; small footprint; required for
|
||||
`.local` resolution from the USB.
|
||||
- **rc.conf.** Add `avahi_daemon_enable="YES"`. `dbus_enable="YES"` is
|
||||
already set in `build.sh:759`; Avahi depends on it.
|
||||
- **nsswitch.conf.** Replace the `hosts:` line with:
|
||||
|
||||
```text
|
||||
hosts: files mdns_minimal [NOTFOUND=return] dns mdns
|
||||
```
|
||||
|
||||
`mdns_minimal` short-circuits non-`.local` lookups back to `dns` so we
|
||||
don't multicast every hostname on the LAN. Trailing `mdns` handles
|
||||
`.local` names not caught by `mdns_minimal`.
|
||||
- **Avahi service file.** No edits. The packaged
|
||||
`/usr/local/etc/avahi/services/ssh.service` advertises `_ssh._tcp` on
|
||||
port 22, which is what we want once `sshd_enable="YES"` is in place
|
||||
(see SSH plan above).
|
||||
- **No package choice churn.** Use `avahi-app` + `nss_mdns`, not
|
||||
`mDNSResponder`. The Avahi stack is already in the live closure and
|
||||
ships the SSH service file we need.
|
||||
|
||||
#### Caveat: multicast-hostile networks
|
||||
|
||||
Some corporate networks, hotel Wi-Fi, and guest VLANs filter multicast
|
||||
traffic. On those networks `clawdie-live.local` will fail to resolve and
|
||||
the operator falls back to either the Tailscale path (if configured) or
|
||||
the DHCP-IP path. Worth knowing before assuming "mDNS doesn't work" is a
|
||||
build bug.
|
||||
|
||||
#### Testing hooks (live USB, after boot)
|
||||
|
||||
```sh
|
||||
service avahi_daemon status
|
||||
avahi-browse -at # should show _ssh._tcp on clawdie-live
|
||||
avahi-resolve-host-name clawdie-live.local # should return an IP
|
||||
|
||||
# From another machine on the same LAN:
|
||||
ssh clawdie@clawdie-live.local
|
||||
scp clawdie@clawdie-live.local:/var/tmp/clawdie-xsession-errors-last.log .
|
||||
```
|
||||
|
||||
Static checks for TESTING.md Level 1 (after image mount):
|
||||
|
||||
```sh
|
||||
grep -E '^avahi_daemon_enable="YES"' /mnt/etc/rc.conf
|
||||
grep -E '^hosts:.*mdns_minimal' /mnt/etc/nsswitch.conf
|
||||
pkg -r /mnt info -e avahi-app
|
||||
pkg -r /mnt info -e nss_mdns
|
||||
test -f /mnt/usr/local/etc/avahi/services/ssh.service
|
||||
```
|
||||
|
||||
## Audio stack — see BUILD.md
|
||||
|
||||
The PulseAudio creep investigation moved to `BUILD.md` once the
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue