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 `:4411:b105:50:45` — "FOR ALL BIOS" plus `10.0.50.45` read straight off the address. That is also the durable fix for the IPv6 resolver the ESH UDM now advertises via RDNSS, which currently points at a MAC-derived SLAAC address that dies if the NIC changes. - -_As of 2026-08-23 — a long multi-party ops session. The Anaheim tunnel cipher is now settled (closed: the remedy does not exist). The one thing still open with the operator is how long WAN admin on ana-gw stays open._ - +- **🟢 ESH IPv6 LAN naming scheme — now a real doc, and LIVE on one host.** Six ESH LANs carry an 8-hex-digit phrase in the interface identifier (`esh-server`=`4411:B105` "FOR ALL BIOS", `esh-mgmt`=`15DA:B055` "IS DA BOSS", `esh-userland`=`CAFE:4411`, `esh-iot`=`4DBA:D107`, `esh-cameras`=`1533:FACE5`, `Default`=`4BA5:3417`, plus `4411:DBAD` reserved for a future DMZ). **Canonical: [`docs/pfi/ipv6-naming-scheme.md`](docs/pfi/ipv6-naming-scheme.md)** — full table, address structure, what UniFi can and cannot name, and the `if-up.d` recipe. ⚠ This entry was once the ONLY record and a `memory: snapshot` (`837fa36`) deleted it; it took a transcript hunt to recover. It is a convention, not temporal state — **the doc is now the home; do not let this line become the only copy again.** First live use 2026-08-24: AdGuard on esh-docker-vm at `2607:73c0:402:1d02:4411:b105:50:45`, which is what the ESH UDM advertises to clients as its IPv6 resolver. - **🔒 ana-gw WAN admin is CLOSED again (2026-08-23, operator-directed) and the FortiGate is scheduled for replacement.** The cutover contingency window is over: `wan1 allowaccess` is back to **`ping` only** (https + ssh removed) and `infra-ops` trusthost is back to **10.0.0.0/8 only** — verified from two sites that 443 and 22 are closed, and that management still works over the tunnel at 10.250.0.1. **There is no longer any out-of-band path to ana-gw**; if both tunnels drop, it is console-only. Re-open = `set allowaccess ping https` on wan1 plus widening the infra-ops trusthost (both one-liners, recorded in auto-memory). ⚠ **Port 80 on 38.120.12.42 is still open and it IS the FortiGate** — the FortiOS **ACME HTTP-01 challenge listener**, opened by `config system acme / set interface "wan1"`, which **bypasses `allowaccess` by design**. Body is literally `ACME Access Only` (403, 101 bytes) for every path; confirmed by sniffer showing `wan1 out 38.120.12.42.80 -> ...: syn ack`. Not a DNAT (only two VIPs exist on .42: Kokoro `:8880`, wg `:31337`) and not an admin surface — it serves only challenge tokens. Closing it = `config system acme` unset interface, which also ends cert renewal. - **✅ CLOSED 2026-08-23: the Anaheim tunnel "problem" is mostly a measurement artefact, and the AES-GCM cutover is impossible.** Operator authorised the cutover; it was attempted NH3-side-first and **cannot be done — UniFi's manual site-to-site IPsec implements no AES-GCM** (8 spellings rejected `api.err.InvalidPayload` against a passing `aes256` control; accepted enum is `aes128/aes192/aes256/3des` only). This blocks the ESH tunnel too, since both far ends are UDMs. The framing was also wrong twice over: **NH3's uplink is 1 Gbps** (not Anaheim's 2 Gbps — that is the real ceiling), and the tunnel does **692 Mbit/s at 8 streams** (the original stopped at 4 and reported ~550). Against WireGuard on the same UDM and uplink, the gap collapses from 2.3× at one stream to **15% at eight** — so re-architecting onto WireGuard is not worth it. Real constraint = **per-stream ~245 Mbit/s**, both endpoints idle. **Standing mitigation: parallelise bulk transfers (2.8× for free); for single-stream NFS use `nconnect=N`** — the `/mnt/smithy` mount on ana-ml2 at 24.7 MB/s is exactly this case and is the obvious test. FortiGate phase2 `pfi-ana-nh3` was left widened to `aes256-sha1 aes256gcm` (inert while the peer offers only CBC); UDM verified byte-identical to its pre-change snapshot. → `persistent-memory.d/2026-08-23-anaheim-ipsec-tunnel-ceiling.md`