diff --git a/docs/pfi/ipv6-naming-scheme.md b/docs/pfi/ipv6-naming-scheme.md new file mode 100644 index 0000000..88cf470 --- /dev/null +++ b/docs/pfi/ipv6-naming-scheme.md @@ -0,0 +1,133 @@ +# ESH IPv6 naming scheme + +Every ESH LAN carries an **eight-hex-digit phrase** as the first half of the +interface identifier. Picked 2026-08-18/19. This file is the canonical record. + +> **Why this file exists.** The scheme originally lived as a single line in +> `persistent-memory.md` and was silently deleted by a `memory: snapshot` +> commit (`837fa36`). Recovering it took a hunt through session transcripts to +> find the commit that had held it. A naming convention is not temporal state — +> it belongs in a document, so it now is one. + +## The names + +| network | hex | reads as | +|---|---|---| +| `Default` | **`4BA5:3417`** | A BASE FOR IT | +| `esh-mgmt` | **`15DA:B055`** | IS DA BOSS | +| `esh-server` | **`4411:B105`** | FOR ALL BIOS | +| `esh-userland` | **`CAFE:4411`** | CAFE FOR ALL | +| `esh-iot` | **`4DBA:D107`** | FOR DA BAD IOT | +| `esh-cameras` | **`1533:FACE5`** | I SEE FACES | +| *(reserved)* DMZ | **`4411:DBAD`** | FOR ALL DA BAD | + +The DMZ name is **claimed against a network that does not exist yet** — there is +no DMZ on the ESH UDM. Do not reuse it. + +Substitutions are the standard hexspeak set: `0`→O, `1`→I/L, `5`→S, plus letters +that are already native hex (`A`–`F`). Anything outside `0-9a-f` is not +expressible — `b0ss` and `c00l` do **not** work, which is why the set above uses +`B055` and avoids `c00l` entirely. + +House style, arrived at rather than designed: **eight digits, and a complete +phrase rather than a single word.** Words are allowed to straddle the group +boundary (`4DBA:D107` is `4·D·BAD·107`); the phrase reads through the colon. + +## Address structure + +``` +2607:73c0:402:1d02 : 4411:b105 : 50 : 45 +└──── ISP /64 ────┘ └ segment ─┘ └ 10.0.50.45 ┘ +``` + +- **Prefix** — Cityside's, not ours to name. ESH holds a `/56` + (`2607:73c0:402:1d00::/56`, 256 × /64); the subnet id is assigned by UniFi's + `ipv6_pd_prefixid`. `esh-cameras` is `1d00`, `esh-server` is `1d02`. +- **Segment word pair** — 32 bits, from the table above. +- **Host** — the last two IPv4 octets, written as literal digits so they read + straight off the address. `10.0.50.45` → `:50:45`. + +The scheme lives entirely in the **interface identifier**, so it is +**delegation-size independent**. It works identically on a `/56`, a `/48`, or +NH3's single `/64`. It never competes with the subnet id, which is far too small +to hold a word (8 bits at ESH — two hex digits). + +Note: `4411:b105:50:45` fills all four host groups, so there is **no `::`** in +these addresses. Writing `...::4411:b105:50:45` is malformed and will be +rejected. + +## What can and cannot carry a name + +| slot | nameable? | +|---|---| +| `/64` subnet id (`ipv6_pd_prefixid`) | **No** — 8 bits at ESH, two hex digits, no room for a word | +| the gateway's own address | **No** — fixed at `::1` by UniFi, no field for it | +| a UniFi *client* reservation | **No** — UniFi has no IPv6 equivalent of `use_fixedip` | +| **a host taking its own address** | **Yes** — this is the one that works | + +⚠ **The original note concluded these names could never appear in a `dig` or +`ip -6` output. That is wrong.** The first three rows are correct, but they only +establish that *UniFi* cannot assign the address. A Linux host can simply take +one within its own advertised prefix, and the router gets no vote. Appliances +with no shell — cameras, most IoT — genuinely cannot, so `1533:FACE5` and +`4DBA:D107` are likely to stay documentation-only. + +## Applying it to a host + +Do **not** use an `iface … inet6 static` stanza: on Debian that sets +`accept_ra=0`, killing SLAAC and the IPv6 default route — a good way to strand a +headless box. Use an `if-up.d` hook that derives the live prefix instead. + +Live example, `/etc/network/if-up.d/ipv6-scheme-addr` on `esh-docker-vm`: + +```sh +#!/bin/sh +[ "$IFACE" = ens18 ] || exit 0 +( + i=0 + while [ $i -lt 30 ]; do + PFX=$(ip -6 -o addr show dev "$IFACE" scope global 2>/dev/null \ + | awk '{print $4}' | cut -d/ -f1 | head -1 | cut -d: -f1-4) + if [ -n "$PFX" ]; then + ip -6 addr replace "${PFX}:4411:b105:50:45/64" dev "$IFACE" && exit 0 + fi + sleep 2 + i=$((i + 1)) + done +) >/dev/null 2>&1 & +exit 0 +``` + +Three deliberate properties: + +- **The prefix is derived, never hardcoded** — self-heals if Cityside + re-delegates. +- **Backgrounded with a retry** — SLAAC may not have landed when `if-up.d` runs, + and a hook that blocks or fails would stall interface bring-up. +- **Additive** — `/etc/network/interfaces` already sources `interfaces.d/`; + nothing existing is edited, and removal is one `rm`. + +Remaining gap: a *mid-life* prefix change is only picked up at the next +interface-up. A timer would close it; not worth building until the prefix is +observed to actually move. + +## Deployed + +| host | address | status | +|---|---|---| +| `esh-docker-vm` (AdGuard) | `2607:73c0:402:1d02:4411:b105:50:45` | **live** 2026-08-24 | + +This is not decorative. The ESH UDM advertises an IPv6 resolver to clients via +RDNSS, and macOS prefers it over the DHCPv4-supplied one — so whatever sits +there is what resolves `*.internal` for every Mac on the network. It previously +pointed at AdGuard's **MAC-derived SLAAC address**, which would break if that +VM's NIC ever changed. It now points at the scheme address, which will not. + +Both `esh-userland` and `esh-server` advertise it +(`dhcpdv6_dns_auto=false` + `dhcpdv6_dns_1=
`); verified on the wire by +soliciting an RA and parsing option type 25. See +[`reference_unifi_dns_rdnss_limits`] in auto-memory for why that field is only +honoured when an explicit server is supplied. + +Natural next candidates, both on `esh-server` and both real Linux hosts: +`esh-pve-nas` → `…:4411:b105:50:55`, `esh-vm-db` → `…:4411:b105:50:60`. diff --git a/persistent-memory.md b/persistent-memory.md index 23dc9e7..17f4886 100644 --- a/persistent-memory.md +++ b/persistent-memory.md @@ -108,16 +108,7 @@ no longer deployed sidecars here. See Recent decisions.) (no NOPASSWD)** — stage model pulls to `/home`, not root-owned `/worktank`. ## Current state / in-flight -- **🟡 ESH IPv6 LAN naming — a DOCS CONVENTION ONLY, not wire-level.** Fun hexspeak names picked 2026-08-18 for the six ESH LANs: **RESERVED for a future DMZ** = **4411:DBAD** ("FOR ALL DA BAD" — no DMZ network exists on the ESH UDM yet; name claimed 2026-08-19 against the day one is built). `esh-cameras`=**1533:FACE5** ("I SEE FACES" — operator's pick 2026-08-19, and the best of the set), `esh-mgmt`=**15DA:B055** ("IS DA BOSS" — 15=IS, DA literal, B055=BOSS; revised 2026-08-19), `esh-server`=**4411:B105** ("FOR ALL BIOS" — operator's pick 2026-08-19; shares the 411 with userland's CAFE:4411), `esh-userland`=**CAFE:4411** ("CAFE FOR ALL" — operator's pick 2026-08-19; 411 also being US directory assistance is a bonus), `esh-iot`=**4DBA:D107** ("FOR DA BAD IOT" — 4=FOR, D=DA, BAD, 107=IOT; same 8 digits, re-glossed 2026-08-19), Default=**4BA5:3417** ("A BASE FOR IT" — operator's pick 2026-08-19; 8 digits, words straddle the group boundary like `4DBA:D107`). **Investigated and confirmed these CANNOT be made literal on the wire**: (1) a network's only nameable slot is its `/64` subnet id (`ipv6_pd_prefixid`), which is 2 hex digits (0-255) — not enough room to spell a 4-char word; (2) the gateway's own address is fixed at `::1` by the UniFi platform, no field to customize it (`ipv6_aliases` exists but schema unknown, not attempted blind); (3) UniFi has **no IPv6 equivalent of `use_fixedip`/`fixed_ip`** (checked the client schema directly) — individual devices cannot be pinned to a chosen v6 address the way v4 static reservations work; SLAAC devices self-assign via EUI-64 (MAC-derived, stable) or privacy-extension (random, rotates). So the names are a mnemonic for humans/docs, not something that will ever appear in a `dig`/`ip -6` output. Only `esh-cameras` has v6 live at all (`2607:73c0:402:1d00::/64`, PD from the ESH `/56`); the other five stay `ipv6_interface_type: none` pending a firewall-policy pass before enabling SLAAC fleet-wide (LAN devices would get globally reachable addresses). - - **♻ RESTORED 2026-08-24** — this entry was silently dropped by the `memory: snapshot` commit `837fa36` and took a long hunt to recover from `8be8a51`. It is a naming convention, not temporal state: **do not prune it in a snapshot.** - - ⚠ **The "cannot ever appear in a dig/ip -6 output" claim above is now PARTLY WRONG and should not be trusted.** Points (1) and (2) still hold — UniFi cannot name a subnet id or the gateway address. But point (3) only means *UniFi* cannot assign a host address; **any Linux host can simply take one itself**, and that makes the names real on the wire. Verified 2026-08-24 on esh-docker-vm: `/etc/network/interfaces` sources `interfaces.d/`, and an `/etc/network/if-up.d/` hook can derive the live prefix and `ip -6 addr replace` a scheme address at boot without touching existing config or disturbing SLAAC. - - **First real use, pending operator go-ahead:** AdGuard on `esh-server` at `