NTP-Governance, SSDP-Relay live, WLAN-Config zurueck unter Drift-Kontrolle

92/92 compliant, 0 Drifts (vorher 71/76 bei 19 Rules -- jetzt 23 Rules).

NTP: die Wurzel war doppelt. Der Core hatte keinen eigenen Client, UND sein
Server hielt Stratum 16 fest, weil er eingeschaltet wurde, bevor der Client
synchron war. Der Test, der es aufgeklaert hat: branch einmal auf
at.pool.ntp.org zeigen lassen -- 20 Sekunden bis synchronized, also war der
Client heil und der Server schwieg. Jetzt im Template, per DHCP-Option 42 an
alle Clients ausgeliefert und mit der Rule system-ntp ueberwacht.

TP7.1: SSDP-Relay laeuft als LXC 108 auf pve, zweibeinig in VLAN10+40.
User-bestaetigt: "sonos ist da!". core ether13 traegt dafuer jetzt beide VLANs.

TP28: die APs trugen noch die komplette Standalone-WLAN-Config aus TP3 --
wirkungslos, aber sie haette als Soll totes Zeug zur Absicht erklaert.
Abgeraeumt, ohne einen einzigen Client zu verlieren (30 vorher, 30 nachher).
Die fuenf wifi-*-Features haengen jetzt am Core, dazu drei neue Rules
(wifi-capsman, wifi-provisioning, wifi-cap).

Gelernt: [find !dynamic] ist auf /interface wifi configuration ein
SYNTAXFEHLER, kein Filter -- der erste Anlauf aenderte nichts und meldete
trotzdem "Plan Completed".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 06:04:28 +02:00
parent 5cc62b29c1
commit c709c9da6b
6 changed files with 244 additions and 57 deletions

View File

@@ -368,7 +368,29 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
iOS-App (mDNS) und HA-Integration decken den Nutzungsbedarf ab; Spotify Connect läuft über Cloud.
- Abh.: TP4 ✅, TP5 (Sonos-Holes) ✅ live.
### TP7.1 — SSDP-Reflector (macOS-Sonos-App über VLAN-Grenze) ▸ 🔜 **IN TP5 GEZOGEN (User-Vorgabe 2026-08-14)** — nicht mehr „vorgemerkt"
### TP7.1 — SSDP-Relay (macOS-Sonos-App über VLAN-Grenze) ▸ ✅ **LÄUFT (2026-08-18)** — User-bestätigt: „sonos ist da!"
- ✅ **Umsetzung:** eigener LXC **108 `mcast-relay`** auf pve (Ubuntu 24.04, 1 Kern, 256 MB, `onboot`),
zweibeinig: `eth0` = **10.40.10.21** (VLAN10), `eth1` = **10.40.40.21** (VLAN40), Default-Route nur
über VLAN10, **kein IP-Forwarding**. Dazu `core ether13` (pve-Port) um `tagged vlan10, vlan40`
erweitert (`routeros/tp7.1-core-ether13-trunk.rsc`). Software: `alsmith/multicast-relay` als
systemd-Unit `multicast-relay.service`.
- **`--noMDNS` ist Pflicht:** mDNS reflektiert bereits der Core (TP7). Zweimal zu reflektieren
erzeugt Duplikate. **`--ssdpUnicastAddr 10.40.10.21`** ist ebenfalls noetig — die Sonos
antworten auf einen M-SEARCH per **Unicast**, und diese Antworten muessen zurueckgereicht werden.
- 🔑 **Warum zwei Beine zwingend sind** (Christophs Frage „vlan40 sollte keinen relay benoetigen?!?"):
SSDP ist **link-lokales Multicast mit TTL 1**. Der M-SEARCH des MacBooks verlaesst VLAN10 nie, die
`ssdp:alive`-NOTIFYs der Sonos verlassen VLAN40 nie. Ein Relay kann nur kopieren, was es selbst
hoert — es **muss** Mitglied beider Broadcast-Domaenen sein. Routing hilft wegen TTL 1 nicht, und
`forward accept vlan10<->vlan40` ist laengst offen: es scheitert **vor** dem Verbindungsaufbau, an
der Entdeckung. Dass AirPlay funktionierte, passt genau ins Bild — das ist mDNS.
- 🎯 **Beweis im Log:** `[Sonos Discovery] Relayed 268 bytes from 10.40.10.183:49358 on eth0 [ttl 64]
to 255.255.255.255:1900 via eth1/10.40.40.21` — echte Suchrufe beider Macs (`.10.183`, `.10.82`).
- ⚠️ **Falle beim Selbsttest:** ein M-SEARCH **vom Relay-Host selbst** wird nicht weitergereicht
(Loop-Schutz: das Werkzeug ignoriert eigene Quelladressen). Mein synthetischer Test meldete
deshalb 0 Antworten, waehrend die App bereits funktionierte. **Aus dem Relay heraus laesst sich
der Relay nicht pruefen** — entweder am echten Client testen oder am Log mitlesen.
- **Keine Firewall-Arbeit noetig:** der Relay spricht in beiden VLANs jeweils lokal; das trifft die
`forward`-Kette nicht.
- 📌 **Status-Update 2026-08-14:** Symptom vom User erneut bestätigt — **iOS-App ✅, HA-Sonos-Panel ✅ (steuern/gruppieren), macOS-Desktop-App findet die Umgebung nicht.** Damit ist das Bild vollständig: alles, was **mDNS** spricht, funktioniert; nur der **SSDP**-Weg fehlt. Der Fix wird **Bestandteil des TP5-Pakets** (gemeinsamer Test mit Deny-by-default statt zweimal dieselbe Strecke prüfen). ⚠️ **Nicht als Firewall-Problem fehldiagnostizieren:** `forward accept vlan10↔vlan40` ist längst offen — es scheitert an der Discovery, nicht am Datenpfad.
- **Bedarf:** macOS-Desktop-Sonos-App auf VLAN 10 findet die Sonos in VLAN 40 nicht (Discovery per SSDP UDP 1900,
RouterOS reflektiert kein SSDP). iOS-App + HA decken den Alltag ab, aber User will die Desktop-App nutzen.
@@ -694,14 +716,21 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
Stelle** eine funktionierende Zeitsynchronisation; dass drei von vier Uhren stimmten, war
Restglueck vom letzten manuellen Stellen. Behoben mit `routeros/tp19-ntp-core-client.rsc`
(`time.cloudflare.com,at.pool.ntp.org`) → Core `synchronized`.
- ⏳ **Rest:** ap1/ap2/branch stehen weiterhin auf `status=waiting`, obwohl der Core jetzt eine
gueltige Quelle ist. ap2s Uhr wurde einmalig von Hand gestellt (17 h Versatz liegt ueber der
NTP-Panic-Schwelle, so weit springt ein Client nicht von selbst) — **alle vier Uhren stimmen
jetzt**, das Einrasten der Clients ist nachzukontrollieren.
- ⚠️ **Governance-Luecke, die dabei auffiel: `/system ntp` hat GAR KEINE Compliance-Rule.**
Die NTP-Konfiguration ist nicht drift-ueberwacht — exakt der Zustand, den **TP26** fuer
`/ip firewall filter` behoben hat. Gehoert nachgezogen, sonst faellt die naechste stille
Aenderung wieder erst ueber falsche Zeitstempel auf.
- 🔴 **Und der letzte Schritt war der unauffaelligste: der Server hielt Stratum 16 fest.** Er war
eingeschaltet worden, **waehrend sein eigener Client noch unsynchronisiert war** — RouterOS
bewertet das nicht von selbst neu. Die Anfragen kamen an (die Firewall-Regel zaehlte mit),
wurden aber unbrauchbar beantwortet, und alle drei Clients blieben auf `waiting`.
**Ein `enabled=no` / `enabled=yes` nach der Synchronisation hat es geloest.**
Der entscheidende Test dorthin: branch einmal auf `at.pool.ntp.org` zeigen lassen — es
synchronisierte in 20 Sekunden. Damit war bewiesen, dass der Client heil ist und der Server
schweigt, statt weiter im Nebel zu stochern.
✅ **Endstand: alle vier Geraete `synchronized`.** (ap2s Uhr musste einmalig von Hand gestellt
werden — 17 h liegen ueber der NTP-Panic-Schwelle, so weit springt kein Client von selbst.)
- ✅ **Governance nachgezogen (2026-08-18):** NTP steht jetzt im **GC-Template** (Core als Quelle
mit oeffentlichem Upstream, branch/APs als Clients auf `10.40.99.1`), wird per **DHCP-Option 42**
(`ntp-server=` je Netz, Christophs Vorschlag) an **alle** Clients ausgeliefert — nicht nur an die
MikroTik-Flotte — und ist mit der neuen ComplianceRule **`system-ntp`** drift-ueberwacht.
Das war exakt der blinde Fleck, den **TP26** fuer `/ip firewall filter` geschlossen hat.
- ✅ **Live-Nachprüfung 2026-08-16 (MikroMCP + CF-API, reine Reads):**
- **`cudy1` ist tot, nicht nur „offline gemeldet":** `core ether11` steht auf `running=false`, **letzter Link-Down 2026-08-08 19:33**, seither kein Link. Die Formulierung „aktiver VLAN1-Leak" ist damit endgültig hinfällig — der **Dual-DHCP-Race hat keine Quelle mehr**. Offen bleibt nur der *physische* Ausbau + Inventar/Doku.
- **`crs326-core` hat keine VLAN1-IP mehr:** `/ip/address` listet nur noch die 7 SVIs + die WAN-DHCP-Adresse — die **Bring-up-Altlast `10.40.41.211` ist weg**. Damit fällt einer der 5 Compliance-Drifts aus TP22 raus, *sobald* wieder **Backup → Intended → Compliance** gelaufen ist (die Compliance vergleicht gegen das letzte Backup, nicht gegen das Gerät — s. TP22-Falle).
@@ -1015,7 +1044,12 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
- **Abh.:** keine harten. **TP15 ✅** (die zu versorgende Hardware steht und hat DC-Eingänge). Verwandt: **TP18** (Garage-Nodes brauchen je Site eine Stromversorgung), **TP11** (USV-Zustand ins Monitoring). **Kein Blocker für TP5/TP6.**
- **Historie:** war bis 2026-08-16 Unterpunkt von TP15 („🔋 DC-USV: MeanWell LRS-150-48 + DDR-120-48 + LiFePO4 20Ah (~€190), 48V-Bus; CRS326 DC-input passt"). Vollständige Recherche inkl. Schaltbild, Effizienzvergleich und Gerätetabelle: `docs/hw-refresh-requirements.md §9` (+ §10 D/E/F für die offenen Fragen).
### TP25 — WLAN-Stabilisierung: Best-Practice-Audit statt Bauchgefühl ▸ ⏳ **SCHRITTE 1–3 DURCH (2026-08-17): beide APs 18 dBm, 20 MHz auf 2,4, überlappungsfrei** — offen: Signal-Boden + Re-Walk — Sammel-TP für Christophs Beobachtungen 1–6
### TP25 — WLAN-Stabilisierung ▸ ⏳ **Funkparameter + Drift-Erkennung durch; offen nur noch Messarbeit** — Sammel-TP für Christophs Beobachtungen 1–6
> **Restliste (Stand 2026-08-18):** Fund A–D ✅ · Drift-Luecke ✅ (mit TP28, 92/92) ·
> **offen: Fund E** (`access-list` mit `signal-range`-Boden — ⚠️ gehoert jetzt auf den **Manager**,
> nicht mehr auf die APs) · **Fund F** (5:05-Takt bei IoT-Trennungen, am Manager nachmessen —
> die AP-Tabellen sind unter CAPsMAN leer) · **Re-Walk + Dead-Spot-Kartierung** (hands-on).
> Alles drei ist Messarbeit gegen die korrigierte Basis, keine Konfigurationsarbeit mehr.
> **Warum eigener TP:** Christoph hat am 2026-08-16/17 sechs konkrete Beobachtungen gemeldet und ausdrücklich
> **einen** TP dafür verlangt. Sie hängen alle an derselben Ursache-Klasse (Funkparameter, die nicht nach Manual
> gesetzt sind), gehören also zusammen. **TP25 übernimmt den offenen Rest von TP3.3** (Re-Walk, Dead-Spot-Kartierung)
@@ -1240,6 +1274,11 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
Deploy die Fixes **nicht** mehr zurückdrehen. *(Bemerkenswert: `width` für 2,4 GHz stand dort die ganze
Zeit korrekt auf `20mhz` — die SoT war richtig, nur das Gerät hat sie nicht befolgt. Der Beweis, dass
das Problem der Inline-Override war und nicht die Datenlage.)*
- ✅ **ERLEDIGT 2026-08-18 (mit dem TP28-GC-Umbau).** Die `wifi-*`-Features haengen jetzt am Core,
die APs sind auf die `cap`-Zeile eingedampft, und drei neue Rules (`wifi-capsman`,
`wifi-provisioning`, `wifi-cap`) decken den Rest ab. **92/92 compliant.** Die unten
beschriebene Luecke auf `/interface wifi` ist damit gegenstandslos: ein CAP hat keine
Inline-Overrides mehr. Der historische Befund bleibt als Begruendung stehen:
- 🔴 **Der Erkennungsteil bleibt offen. Die 18 Compliance-Rules abgefragt — es fehlen genau zwei Sektionen:**
| vorhanden | fehlt |
|---|---|
@@ -1319,7 +1358,38 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
liefert das Entscheidungskriterium). ⚠️ **Berührt TP5:** der Mesh-Verkehr braucht bei deny-by-default eine
explizite `forward`-Zeile — s. TP5 Etappe 2.
### TP28 — WLAN über CAPsMAN auf `crs326-core` ▸ ✅ **CUTOVER DURCH (2026-08-17)** — beide APs sind reine CAPs
### TP28 — WLAN über CAPsMAN auf `crs326-core` ▸ ✅ **KOMPLETT (2026-08-18): Cutover + GC-Modell nachgezogen**
- ✅ **Der offene GC-Rest ist erledigt (2026-08-18).** Die fuenf `wifi-*`-ComplianceFeatures haengen
jetzt am **Core**, der AP-Zweig des Templates ist auf eine einzige Zeile eingedampft
(`/interface wifi cap set discovery-interfaces=vlanXX enabled=yes`).
- 🔴 **Dabei aufgefallen: die APs trugen noch die KOMPLETTE Standalone-WLAN-Config** aus TP3 —
je 2 channel, 6 datapath, 6 security, 7 configuration, 1 steering. Der Cutover vom 08-17 hatte
sie nie abgeraeumt. Wirkungslos (der Manager liefert alles dynamisch), aber sie im Template als
Soll zu rendern hiesse, totes Zeug zur Absicht zu erklaeren — dasselbe Argument wie bei den
defconf-Firewallregeln in TP26. Abgeraeumt mit `routeros/tp28-ap-wifi-reste-abraeumen.rsc`.
- ✅ **Ohne jeden Aussetzer:** vorher/nachher 30 Clients, beide CAPs `Ok`, 7 dynamische VAPs je AP.
Die Sorge vor einem Radio-Re-Apply (TP25/TP3.3: „wirft jeden Client kurz raus") hat sich nicht
bestaetigt — die dynamischen VAPs tragen ihre Werte **inline** (`datapath.vlan-id=…`) und
referenzieren kein lokales Objekt; nur `wifi1`/`wifi2` hielten noch einen toten
`configuration=`-Verweis, der beim Loeschen folgenlos blieb.
- 🔴 **`[find !dynamic]` ist auf diesen Sektionen ein SYNTAXFEHLER**, nicht bloss wirkungslos:
`/interface wifi configuration` & Co. haben gar keine `dynamic`-Eigenschaft (die gibt es nur auf
`/interface wifi` selbst). Der erste Anlauf lief komplett in die `on-error`-Zweige, aenderte
**nichts** und meldete trotzdem „Plan Completed". Wieder: nur die Gegenpruefung am Geraet zaehlt.
- ✅ **Drei neue ComplianceRules schliessen die letzten WLAN-Luecken:** `wifi-capsman`
(der Manager-Schalter), `wifi-provisioning` (die vier Regeln je `radio-mac` — sie entscheiden,
welcher AP welche Kanaele und Slave-VAPs bekommt) und `wifi-cap` (die CAP-Seite; faellt
`discovery-interfaces` weg, findet der AP seinen Manager nach dem naechsten Reboot nicht mehr).
**Ergebnis: 92/92 compliant, 0 Drifts.**
- ⚠️ **`wifi-security` ist gruen, aber NICHT deploybar.** Die Passphrasen stehen als `<<REDACTED>>`
im Template (User-Entscheid 2026-08-18: alle fuenf Features umhaengen, Platzhalter in Kauf nehmen).
Der gruene Haken beweist nur, dass Soll und Ist dieselbe **Maske** tragen — nicht, dass die
Passphrasen stimmen, und schon gar nicht, dass die Sektion ausgerollt werden koennte. Das steht
als Warnung im Template. Wer sie aendert, liest den Ist-Stand per REST zurueck
(`GET http://10.40.99.1/rest/interface/wifi/security`) — **nicht** aus `wlan-psks.env` oder den
drei Bring-up-Dateien, die voneinander abgeschrieben sind.
- ⚠️ **Die frueher hier notierte „bisher fehlende Rule auf `/interface wifi`" ist gegenstandslos** —
wie vorhergesagt: ein CAP hat keine Inline-Overrides mehr, die driften koennten.
> **Methodenwechsel auf Christophs Anstoß:** *„ich möchte die methode in frage stellen … eine sot ist zwar nett,
> aber wenn sie uns das leben zur hölle macht, verzichte ich auf diese governance."* Der Entscheid vom
> 2026-07-22, CAPsMAN abzuschaffen, ist damit **revidiert**.