Files
esh-pfi-infrastructure/docs/pfi/ipv6-naming-scheme.md
T
vh d127e29fac docs(ipv6): retire the next-candidates line now that all three are done
Replaces it with why the remaining segments have no eligible hosts:
two are appliance-only and three have no IPv6 enabled yet, pending the
firewall-policy pass that SLAAC on a client segment would require.
2026-08-23 22:39:51 -07:00

7.5 KiB
Raw Blame History

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 (AF). 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:

#!/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

All three Linux hosts on esh-server now carry the segment name, with the last two groups reading straight off their IPv4 address:

host address v4 applied via
esh-docker-vm (AdGuard) 2607:73c0:402:1d02:4411:b105:50:45 10.0.50.45 if-up.d on ens18
esh-pve-nas 2607:73c0:402:1d02:4411:b105:50:55 10.0.50.55 if-up.d on vmbr0
esh-vm-db 2607:73c0:402:1d02:4411:b105:50:60 10.0.50.60 if-up.d on ens18

esh-docker-vm's is load-bearing, not decorative: the ESH UDM advertises an IPv6 resolver to clients via RDNSS, 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 have broken if that VM's NIC ever changed. Both esh-userland and esh-server now advertise the scheme address instead (dhcpdv6_dns_auto=false + dhcpdv6_dns_1=<address>), verified on the wire by soliciting an RA and parsing option type 25.

⚠ Proxmox bridges need accept_ra=2 or SLAAC never runs

esh-pve-nas had link-local only despite accept_ra=1, autoconf=1 and IPv6 enabled — every sysctl looked correct. The cause: vmbr0.forwarding = 1 (Proxmox sets per-interface forwarding on bridges), and the kernel ignores RAs on a forwarding interface unless accept_ra is explicitly 2. accept_ra=1 means "accept only if not forwarding", so it silently did nothing.

Fixed in /etc/sysctl.d/60-ipv6-accept-ra.conf on that host:

net.ipv6.conf.vmbr0.accept_ra = 2
net.ipv6.conf.vmbr0.accept_ra_defrtr = 0

accept_ra_defrtr=0 is deliberate — it takes the advertised prefix (so SLAAC configures an address) while declining the default route, so a hypervisor gains an IPv6 identity with no change to its routing behaviour. Verified after: SLAAC address present, v6 default routes still 0, v4 intact.

Expect the same on any other Proxmox node when its LAN gets IPv6.

Getting into a host with no direct root

esh-vm-db refuses key auth for root and infra-ops, and lkraven's sudo wants a password. It is VMID 101 on esh-pve, and the QEMU guest agent runs as uid 0 inside it, so the hook was installed with:

qm guest exec 101 -- /bin/sh -c 'echo <base64> | base64 -d > /etc/network/if-up.d/... '

base64 because quoting a multi-line script through two SSH layers mangles it. Worth remembering as the general path for guests whose credentials are not vaulted.

Every Linux host on esh-server now carries its name. The remaining ESH segments have no eligible hosts: esh-cameras and esh-iot are appliances with no shell, and esh-mgmt, esh-userland and Default are still ipv6_interface_type: none pending the firewall-policy pass — enabling SLAAC there gives every client a globally reachable address.