Compare commits
71 Commits
e474e5e38a
...
claude/luc
| Author | SHA1 | Date | |
|---|---|---|---|
| 0278b3b8ef | |||
| 614025eafb | |||
| 677dade184 | |||
| b20edd6b62 | |||
| a38ed0fe1d | |||
| 5a29c482bd | |||
| 4eba3673b7 | |||
| 2b856d3d42 | |||
| f1d565bc88 | |||
| 43c592e5d4 | |||
| 33b18a08db | |||
| 799b693ffa | |||
| 4aeced30b5 | |||
| 89d94dbd45 | |||
| 6f60e03679 | |||
| 2f4866ca9a | |||
| 8e41268b4b | |||
| b915d02a82 | |||
| efb03979a0 | |||
| 268fd859ab | |||
| 7a20a1db4f | |||
| bca8f6e27e | |||
| d63dc7bb78 | |||
| b200401c5a | |||
| 384f356290 | |||
| e96fca5a52 | |||
| 1625c30fd7 | |||
| 83fd69ef8d | |||
| 56746cb24d | |||
| a0ba87d555 | |||
| 674e5fff0d | |||
| c024f85579 | |||
| 9caf145341 | |||
| 7edf01b021 | |||
| f507c50623 | |||
| f8982df200 | |||
| c23628f62f | |||
| b75336c9db | |||
| 70afb165b7 | |||
| efb0f44fa7 | |||
| ac3a125c82 | |||
| 45e4540cf5 | |||
| e8f58b0e5e | |||
| 05a3fd957f | |||
| bf6d3605b7 | |||
| 8aae0f424f | |||
| 72db50fce2 | |||
| cce88bdcba | |||
| c7e173ec5a | |||
| 1b413b41f3 | |||
| e376651247 | |||
| fde9f1535a | |||
| ab01934c2d | |||
| 46e6a54ecb | |||
| 403b4528b2 | |||
| 20671aefd4 | |||
| c543819a90 | |||
| 012397f194 | |||
| faa4308223 | |||
| 155dbc08f2 | |||
| 284df839db | |||
| 07b595c45a | |||
| 724cfd9a98 | |||
| 3f95a7adf3 | |||
| 335c562323 | |||
| 3ea8d050d2 | |||
| ef19a95747 | |||
| 83bcfaabd0 | |||
| 73fec72abe | |||
| f6283fd813 | |||
| 4cd091379e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -25,3 +25,4 @@ caddy/caddy.env
|
||||
|
||||
# Config-Backups, die Sessions vor destruktiven Edits anlegen (2026-08-30)
|
||||
*.bak-*
|
||||
docs/macmini-vlan20/stacks
|
||||
|
||||
100
CLAUDE.md
100
CLAUDE.md
@@ -6,18 +6,48 @@ DNS/DHCP-Ablösung, WLAN via **CAPsMAN auf dem Core** (TP28, 2026-08-17 — der
|
||||
|
||||
## Pflichtlektüre pro Sitzung (Reihenfolge)
|
||||
|
||||
1. **`docs/teilprojekte.md`** (Quick-Index-Block) — kanonischer Stand, Scope, Abhängigkeiten, **offene** TPs. **1 Read reicht.**
|
||||
1. **Status/Index = Gitea-Board** (seit TP36-Cutover 2026-09-07): [`admin/bf-infra` · Issues](https://gitea.emsenhuber.net/admin/bf-infra/issues) — TP = Issue, Status = Label `status:*`, Gruppierung = `thema:*`. Für den **Detail/Kontext** eines TP dann den `### TPnn`-Prosa-Abschnitt in **`docs/teilprojekte.md`** (aktiv) bzw. **`docs/teilprojekte-archiv.md`** lesen. *(Die frühere „Quick-Index-Block, 1 Read reicht"-Zeile ist überholt — Index/Status stehen nicht mehr in der Datei.)*
|
||||
2. **`docs/handoff-*.md`** (neueste) — wo die letzte Session aufgehört hat.
|
||||
3. Bei Live-Writes oder Inventur: **`docs/cf-tunnel-mapping.md`**, **`docs/teilprojekte-archiv.md`**.
|
||||
4. 🔴 **WLAN/Fund E — HEBEL 1 GESCHEITERT + TP27 durchgezogen:**
|
||||
[`docs/handoff-20260831-tp27-upgrade-und-hebel1-befund.md`](docs/handoff-20260831-tp27-upgrade-und-hebel1-befund.md)
|
||||
— `ft-over-ds=no` hat **nicht** gegriffen (124 `reauthenticating` nach dem Eingriff, zwei erlebte
|
||||
Ausfälle um 13:16 und 14:23). Transaktion `TP25-fund-e-ft-over-ds` **bleibt offen**, **Compliance
|
||||
steht weiter absichtlich auf 134/135**. Nächste Entscheidung: Hebel 2 (`ft=no`) **oder**
|
||||
`wpa2-psk,wpa3-psk` — vorher prüfen, ob 7.24.1 das Verhalten schon verändert hat.
|
||||
Vorstufen: [Eingriff](docs/handoff-20260831-fund-e-hebel1-gezogen.md) · [Befund](docs/handoff-20260831-wlan-fund-e.md).
|
||||
5. ap3-Bring-up 2026-08-30: [`docs/handoff-20260830-ap3.md`](docs/handoff-20260830-ap3.md) — sechs Funde zu Werks-MikroTiks, CAPsMAN und Golden-Config-Lücken.
|
||||
6. Inventur-Befund 2026-08-27: [`docs/handoff-20260827-inventur-und-architektur.md`](docs/handoff-20260827-inventur-und-architektur.md) — Master-Struktur, Asymmetrie, Drift.
|
||||
4. ✅ **TP16.3 §5 durch (2026-09-01):** [`docs/handoff-20260901-tp16.3-paragraph5-flip-durch.md`](docs/handoff-20260901-tp16.3-paragraph5-flip-durch.md)
|
||||
— alle vier oeffentlichen Namen laufen ueber `bf-public`/Caddy; Alttunnel bleiben als Rueckfallebene
|
||||
(§6 offen). Enthaelt den 10-Sekunden-DNS-Fund und drei Messfallen.
|
||||
5. ✅ **WLAN/Fund E — GESCHLOSSEN 2026-09-02: 7.24.1 war die Ursache, nicht `ft-over-ds`:**
|
||||
[`docs/handoff-20260902-tp25-fund-e-messung.md`](docs/handoff-20260902-tp25-fund-e-messung.md)
|
||||
— die Abschlussmessung ergab am 09-02 nur **4 `reauthenticating` in 8,6 h** (alle iPhone `F2:62`,
|
||||
isolierte Einzel, 0 Ausfaelle), Verlauf **218 → 40 → 4**; Vorbedingung geprueft (Core-Uptime 1d18h,
|
||||
`caps joined=0`). Hebel 1 (`ft-over-ds=no`) war widerlegt (6,4 h allein → 124× + 2 Ausfaelle) und ist
|
||||
am 09-01 zurueckgebaut; Hebel 2–4 entfallen, **kein Geraete-Write** (Soll stand: `ft=yes ft-over-ds=yes`,
|
||||
**Compliance 140/140**). **Am 2026-09-04 hat Christoph `ft=no` auf `sec-main` als Dauerzustand
|
||||
entschieden** (Hebel 2 doch gezogen: Template + bf-golden-config + Nautobot-Sync, `wifi-security` gruen).
|
||||
🔴 **Nachtrag 09-04: `ft=no` war NICHT uniform.** ap3 trug einen Werks-Inline `security.ft=yes` auf
|
||||
`wifi1/wifi2` (Bring-up unset `!ft-over-ds`, aber nicht `!ft`; Abnahme zählt nur benannte
|
||||
security-Objekte → Inline-Wert unsichtbar). Gemischtes FT-ESS → Strong-Signal-Abbrüche (−43/−45 dBm)
|
||||
**nur auf ap3** bei 3/3 Strichen. Fix: `!security.ft` auf ap3 (uniform `ft=no`), Quelle
|
||||
`tp28-ap3-phase2-cap.rsc` korrigiert. **Merkregel: nach jeder `sec-main`-FT-Änderung jeden CAP einzeln
|
||||
`get wifiN security.ft` prüfen — CAP-lokale Inline-Overrides sind compliance-unsichtbar.**
|
||||
Der TP25-Kanalplan ist am 09-04 committed (DFS-Frequenzlisten + ap1-Provisioning, **140/140, 0 Drifts**).
|
||||
Offen in TP25 bleibt nur **ap2 unterperformt** (2 m/−80 dBm). Vorstufen:
|
||||
[Befund](docs/handoff-20260831-tp27-upgrade-und-hebel1-befund.md) ·
|
||||
[Eingriff](docs/handoff-20260831-fund-e-hebel1-gezogen.md) ·
|
||||
[Rueckbau](docs/handoff-20260901-fund-e-hebel1-zurueckgebaut.md).
|
||||
6. ap3-Bring-up 2026-08-30: [`docs/handoff-20260830-ap3.md`](docs/handoff-20260830-ap3.md) — sechs Funde zu Werks-MikroTiks, CAPsMAN und Golden-Config-Lücken.
|
||||
7. Inventur-Befund 2026-08-27: [`docs/handoff-20260827-inventur-und-architektur.md`](docs/handoff-20260827-inventur-und-architektur.md) — Master-Struktur, Asymmetrie, Drift.
|
||||
|
||||
## SSoT & Branch-Konvention (TP36-Cutover 2026-09-07)
|
||||
|
||||
- **SSoT-Dreiteilung:** **Index/Status = Gitea-Issues** (`admin/bf-infra`, Labels `status:*`/`thema:*`) ·
|
||||
**Prosa/Detail = Repo** (`docs/teilprojekte.md` aktiv + `teilprojekte-archiv.md`, `### TPnn`-Abschnitte) ·
|
||||
**Live-Gerätedaten = Nautobot** (Compliance-Zahl, RouterOS-Version …). Ein Status ändert sich **in Gitea**,
|
||||
nicht mehr in einer Repo-Datei. Sync-/Abgleich-Werkzeug fürs Archiv: `bin/gitea-tp-sync.py` (Dry-Run default,
|
||||
Token aus `~/.hermes/.env`, **nie ausgeben**).
|
||||
- **Branch-Konvention:** Branch `tpNN-kurz` **jederzeit** mitten in der Session möglich (`git switch -c`,
|
||||
uncommittete Arbeit wandert mit); für Multi-Session-TPs der Normalfall. **Merge nach `main`, sobald der
|
||||
Code/Config des TP steht.** Weil Steuerungs-Updates nach **Gitea** gehen (nicht in `teilprojekte.md`),
|
||||
kollidieren TP-Branches nicht mehr auf der Steuerungs-Doku — nur noch der eigene `### TPnn`-Prosa-Abschnitt
|
||||
wird angefasst.
|
||||
- **TP anlegen/schließen:** neues aktives TP = **direkt als Gitea-Issue** (Labels setzen), Prosa-Abschnitt
|
||||
im Repo dazu; abschließen = Issue `closed`, Prosa wandert bei Bedarf ins Archiv. **Keine Handtabelle mehr.**
|
||||
|
||||
## Was du sofort wissen musst (Inventur 2026-08-27)
|
||||
|
||||
@@ -27,7 +57,7 @@ DNS/DHCP-Ablösung, WLAN via **CAPsMAN auf dem Core** (TP28, 2026-08-17 — der
|
||||
- **`admin/blaueblueten-n8n`** (Gitea) ist Master für terpene-Repo.
|
||||
- **`inventory/` ist tot** (Pipeline seit 2025-06 stale). Live-Daten aus MikroMCP/CF/Portainer.
|
||||
- **`mcp/INVENTORY.md`** ist BF-Netz-SSoT; `~/.claude.json`/`opencode.jsonc` sind globalere Werkzeugkästen.
|
||||
- **terpene.teilzeitladen.xyz**: Worker läuft auf Mac mini (`10.40.20.167:8890`), **kein Caddy-Block, kein CF-Tunnel** — Backfill via DB-Migration blockiert (Handoff 2026-08-27).
|
||||
- **Terpenfinder = `420.teilzeitladen.xyz`** (CF-Worker, Repo `admin/blaueblueten-n8n`, hinter CF Access), **kein Caddy, kein Mac mini im Pfad**. `terpene.*` **existiert nicht und soll es nicht** (live geprüft 2026-09-10). Einziger terpene-benannter CF-Gegenstand: der **interne** Tunnel `terpene-db` (`f2d2fc8a`, ohne öffentlichen Hostname, Hyperdrive→VPC→Postgres, s. `docs/cf-tunnel-mapping.md` §17). ⚠️ **Grenze:** blaueblüten ist ein eigenes Projekt — nicht anfassen. *(Die frühere „terpene.teilzeitladen.xyz:8890 via Tunnel"-Zeile war veraltet — bf-mm ist gelöscht.)*
|
||||
- **shelly-mcp / portainer-mcp bewusst NICHT als MCP-Client** (User-Direktive 2026-08-28): shelly-mcp-Container auf DS923 wird via **Portainer-API** (Skript-Aufrufe, `mcp/portainer/.env` als Token-Quelle) deployt, nicht via MCP-Protokoll. Inventar-Eintrag spiegelt das. `mcp-host-policy.md` ist SSoT für die Host-/IP-Konvention.
|
||||
- **Mac mini `10.40.20.167`** ist der **n8n-Host** (n8n `:5678`, n8n-redis `:6379`, n8n-mcp `:3001`) — **NICHT** der zentrale MCP-Host. Performance-Überlegung: MCP-Clients würden auf dem macmini (User-Workstation) laufen und die Box zusätzlich belasten; deshalb liegt der MCP-Host auf der **DS923** (`nas-bf`, Portainer Endpoint 14). gitea-mcp läuft aktuell noch auf dem macmini (historisch, eigene Container-Definition dort) — gehört **bei Gelegenheit** auf die DS923 umgezogen (separater Punkt, **nicht** Teil dieser Session). Container-Definitionen für n8n leben auf dem macmini (Docker Desktop); FQDN→Backend-Mapping im `caddy/Caddyfile`.
|
||||
|
||||
@@ -35,12 +65,15 @@ DNS/DHCP-Ablösung, WLAN via **CAPsMAN auf dem Core** (TP28, 2026-08-17 — der
|
||||
|
||||
Wenn während einer Session ein neues Teilprojekt, eine Abhängigkeit oder ein Querschnittsthema sichtbar wird, das bisher in keinem TP abgebildet ist:
|
||||
- Vorschlagen und mit dir abstimmen (nicht eigenmächtig anlegen).
|
||||
- Auf dein Okay hin anlegen: Quick-Index-Zeile + `### TP<n>`-Abschnitt mit Status `🔜`, Scope,
|
||||
Abhängigkeiten, Abgrenzung. Nächste freie Nummer vergeben (höchste vergebene + 1; Lücken aus
|
||||
verworfenen TPs bleiben frei).
|
||||
- Ist-Stand-Block mitziehen (Datum, betroffene Zeilen).
|
||||
- Auf dein Okay hin anlegen: **Gitea-Issue** `TPnn — <Kurztitel>` mit Labels `status:🔜`(todo) +
|
||||
passendem `thema:*` + Body (Anriss + Verweis auf den Prosa-Abschnitt) **und** einen
|
||||
`### TP<n>`-Prosa-Abschnitt in `docs/teilprojekte.md` (Scope, Abhängigkeiten, Abgrenzung).
|
||||
Nächste freie Nummer vergeben (höchste vergebene + 1; Lücken aus verworfenen TPs bleiben frei).
|
||||
- **Status/Reihenfolge/„was lief zuletzt" gehen ins Gitea-Issue** (Label ändern, Kommentar), **nicht**
|
||||
in eine Quick-Index-Tabelle oder einen Ist-Stand-Block — die gibt es seit dem TP36-Cutover (2026-09-07)
|
||||
nicht mehr in der Datei.
|
||||
|
||||
**Abgeschlossene TPs** stehen seit 2026-08-23 in `docs/teilprojekte-archiv.md` (Volltext, unverändert, mit Inhaltsverzeichnis). **Ein TP wandert erst ins Archiv, wenn nichts mehr daran zu tun ist — und wieder zurück, sobald doch etwas dazukommt.** Ein archiviertes TP ist ein *geschlossenes Ticket, kein versiegeltes*: bei neuer Arbeit an derselben Baustelle wandert der **Volltext zurück** nach `teilprojekte.md` (Zeiger bleibt im Archiv), **kein** Zwillings-TP mit neuer Nummer (Christoph-Direktive 2026-08-30, erster Fall TP28/`ap3`) — und der **Ist-Stand-Block wird bei jeder Änderung mitgezogen**, nicht nur der betroffene TP-Abschnitt.
|
||||
**Abgeschlossene TPs** stehen seit 2026-08-23 in `docs/teilprojekte-archiv.md` (Volltext, unverändert, mit Inhaltsverzeichnis) und ihr Gitea-Issue ist `closed` (Label `status:✅`/`❌`). **Ein TP wandert erst ins Archiv, wenn nichts mehr daran zu tun ist — und wieder zurück, sobald doch etwas dazukommt** (Issue dann `reopen`). Ein archiviertes TP ist ein *geschlossenes Ticket, kein versiegeltes*: bei neuer Arbeit an derselben Baustelle wandert der **Volltext zurück** nach `teilprojekte.md` (Zeiger bleibt im Archiv), **kein** Zwillings-TP mit neuer Nummer (Christoph-Direktive 2026-08-30, erster Fall TP28/`ap3`) — nur noch der betroffene `### TPnn`-Prosa-Abschnitt wird angefasst.
|
||||
|
||||
---
|
||||
|
||||
@@ -206,6 +239,41 @@ GW je VLAN = `.1` (crs326-core L3) · Mgmt VLAN99: core `.99.1`, branch `.99.2`,
|
||||
Gesetz** — und ob sie dem konkreten Dienst überhaupt gilt.
|
||||
- **Schwere Container laufen weiterhin auf NAS/pve**, nicht am Router (Caddy, AdGuard: die eine Config
|
||||
ändert sich staendig, die andere schreibt dauernd Logs auf NAND).
|
||||
- ⏱️ **Ein konstanter 10-Sekunden-Hänger ist ein DNS-Timeout, kein Lastproblem** (Fund 2026-09-01,
|
||||
TP16.3-Randbefund). `gitea` hing bei ~10 % der Anfragen exakt 10,1 s — quer über Web-UI,
|
||||
`/api/healthz` **und** den Git-Pfad, also kein Rendering. Ursache: **MariaDB (LXC 302) hatte
|
||||
`skip-name-resolve` auskommentiert** und machte bei **jeder neuen Verbindung** einen
|
||||
Reverse-Lookup, während ihr `/etc/resolv.conf` noch auf den toten `10.40.41.254` zeigte
|
||||
(glibc: 5 s × 2 Versuche = 10 s). Pool-Verbindungen waren schnell ⇒ es wirkte sporadisch.
|
||||
🔑 **Drei Merkregeln daraus:** (a) **immer gegen eine zweite Sache messen, die denselben Weg
|
||||
nimmt** — `vw`/`hass` über dieselbe Strecke hatten 0 von 30 Hängern, das hat CF, Tunnel, Firewall
|
||||
und Caddy in einem Schritt entlastet; (b) **wer an einer DB hängt, sagt die Verbindungstabelle**
|
||||
(`ss -tn | grep 3306`), nicht die Vermutung — hier hingen **Vaultwarden, Home Assistant und gitea**
|
||||
an derselben MariaDB, und die Annahme „Vaultwarden nutzt SQLite" war schlicht falsch;
|
||||
(c) **ein toter Resolver ist selten allein** — der Sweep über alle LXCs fand **fünf** Container mit
|
||||
`10.40.41.254`. Sweep: `for c in $(pct list|awk 'NR>1{print $1}'); do pct exec $c -- grep ^nameserver /etc/resolv.conf; done`
|
||||
- 🔌 **`networking.service` failed bei funktionierendem Netz = tote `auto`-Stanzas in
|
||||
`/etc/network/interfaces`** (Ursache gefunden + behoben 2026-09-01). In vier LXCs standen dort noch
|
||||
Einträge aus dem **alten VLAN1-Schema** (`eth0` → `10.40.41.x`) und aus früheren Versuchen
|
||||
(`veth16`, `veth24`, Tippfehler `eth01`) — auf Interfaces, die es im Container gar nicht gibt.
|
||||
`ifup -a` scheitert daran, das echte `veth20` kommt trotzdem hoch. **Fix:** nur die Stanzas
|
||||
entfernen, deren Interface in `ip -br link` fehlt (`lo` und die echten behalten), Backup daneben.
|
||||
🔴 **Abnahme ist ein echter Reboot, nicht `systemctl is-active`** — der Servicestatus sagt nichts
|
||||
darüber, ob beim nächsten Start etwas hochkommt.
|
||||
- 🧪 **Ein Messwerkzeug, das etwas anderes beantwortet als die Frage, kostet mehr Zeit als der Fehler**
|
||||
(zweimal in einer Nacht, 2026-09-01). (a) **`nc -z` lieferte falsch-negative** „Port zu" für neun
|
||||
Dienste gleichzeitig — inklusive des SSH-Ports, über den die Session gerade arbeitete; `curl` bekam
|
||||
von demselben Host **HTTP 200 in 24 ms**. **Bei „alles gleichzeitig kaputt" zuerst das eigene
|
||||
Werkzeug verdächtigen**, dann das Netz: ein Python-Socket oder `curl` entscheidet in Sekunden.
|
||||
(b) **Ein Firewall-Zähler taugt nicht als Wegbeweis**, wenn der Client die Verbindung offenhält
|
||||
(`cloudflared`): er zählt nur NEUE Verbindungen und steht still, obwohl alles läuft — richtig ist
|
||||
die **Verbindungstabelle** (`/ip firewall connection`).
|
||||
- 🔌 **`networking.service` kann in einem LXC dauerhaft `failed` sein, ohne dass das Netz fehlt** —
|
||||
und dann startet alles mit `After=network-online.target` nach einem Reboot **nicht**
|
||||
(Fund 2026-09-01: `101`, `102`, `106`, `107`; **influxdb2 kam nach dem Neustart nicht hoch**,
|
||||
Unit `enabled`, **kein Startversuch im Journal**). Fällt nur auf, wenn man neu startet — die
|
||||
Container liefen 13+ Tage. **Vor jedem geplanten LXC-Neustart `systemctl --failed` lesen und
|
||||
danach die Ports gegen vorher vergleichen**, sonst verliert man still einen Dienst.
|
||||
- **VLAN20-Docker-Hosts: Host-DNS nach dem Umzug prüfen (2026-07-10, TP14.2a):** NAS + pve-LXC zeigten `/etc/resolv.conf` noch auf totes `.41.254` → `docker pull` ghcr scheitert (`EAI_AGAIN`, aber Egress ok!). Fix = `.20.1`: LXC `pct set 400 --nameserver 10.40.20.1`; **Synology-Falle: DSM-„Allgemein"-DNS ≠ was `dockerd` liest** — Interface zieht DNS per DHCP → Fix an der *Netzwerkschnittstelle* „DNS manuell". Laufende Container frieren den `127.0.0.11`-Upstream zum Erstellzeitpunkt ein (Recreate nötig). Merkregel: `docker-pull-hängt` + `dns.lookup EAI_AGAIN` aber `TCP zu ghcr-IP:443 ok` = toter Resolver, nicht Egress.
|
||||
- 📜 **~~ALLNET VLAN-DB (TP1)~~ — historisch.** Die VLAN-Semantik gilt weiter (**40=MEDIA, 50=UNTRUSTED**), die Portangaben (GE1/GE2/GE8) beziehen sich auf ein ausgebautes Gerät.
|
||||
- **ap2 hängt an `crs326-branch ether24`** (Trunk, native VLAN1 + tagged 10-99); **branch-Uplink `ether1` → `crs326-core ether8`** (korrigiert 2026-08-16 — die frühere Angabe „→ sw1 GE8" stammt aus der Zeit vor dem Core-Tausch; MAC-hart belegt in TP22 Schritt 5).
|
||||
|
||||
18
__init__.py
Normal file
18
__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
"""Macht die bf-infra-Repo-Wurzel zu einem regulären Python-Paket.
|
||||
|
||||
🔴 LOAD-BEARING — NICHT löschen (sonst laden die Nautobot-Jobs nicht mehr).
|
||||
|
||||
Nautobot klont dieses Repo nach GIT_ROOT/bf_infra/ und lädt Jobs über
|
||||
`import_modules_privately()` → `pkgutil.walk_packages([GIT_ROOT])`. walk_packages
|
||||
entdeckt ausschließlich *reguläre* Pakete (mit __init__.py), niemals
|
||||
Namespace-Packages (Verzeichnisse ohne __init__.py). Ohne diese Datei ist
|
||||
`bf_infra` für den Loader unsichtbar und `jobs/` wird nie importiert — Symptom:
|
||||
Git-Sync SUCCESS, aber Log "No jobs were registered on loading the
|
||||
`bf_infra.jobs` submodule" und kein Job-DB-Eintrag.
|
||||
|
||||
Der module_path-Filter des Loaders (["bf_infra","jobs"]) importiert nur
|
||||
`bf_infra` + `bf_infra.jobs.*`; die übrigen Verzeichnisse (nautobot/, routeros/,
|
||||
bin/, …) bleiben unangetastet und laufen weiter als Standalone-Skripte.
|
||||
|
||||
Verifiziert 2026-09-10 (Nautobot 3.1.7, Python 3.14) — TP44 Teil B.
|
||||
"""
|
||||
@@ -13,7 +13,9 @@ http:
|
||||
session_ttl: 30d
|
||||
users:
|
||||
- name: admin
|
||||
password: $2a$10$ue8PEedG4t2JRyT83XiGHeqIU4PFRzhn8rjDOZGYGt0sFC2qju2fi
|
||||
password: '!on-device (siehe ~/.secrets + Gerät)'
|
||||
- name: automation
|
||||
password: '!on-device (siehe ~/.secrets + Gerät)'
|
||||
auth_attempts: 5
|
||||
block_auth_min: 15
|
||||
http_proxy: ""
|
||||
@@ -202,69 +204,9 @@ filtering:
|
||||
- domain: gitea.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: nautobot.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: ds-bf.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: ccu.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: iobroker.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: z2m25.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: pve-mcp.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: ha-mcp.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: n8n-mcp.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: gitea-mcp.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: pve.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: portainer.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: pbs.emsenhuber.net
|
||||
answer: 10.40.20.40
|
||||
enabled: true
|
||||
- domain: macmini.emsenhuber.net
|
||||
answer: 10.40.20.167
|
||||
enabled: true
|
||||
- domain: mfc.emsenhuber.net
|
||||
answer: 10.40.10.6
|
||||
enabled: true
|
||||
- domain: tv.emsenhuber.net
|
||||
answer: 10.40.40.11
|
||||
enabled: true
|
||||
- domain: docker.emsenhuber.net
|
||||
answer: 10.40.20.126
|
||||
enabled: true
|
||||
- domain: platform-pg.emsenhuber.net
|
||||
answer: 10.40.20.20
|
||||
enabled: true
|
||||
- domain: core.emsenhuber.net
|
||||
answer: 10.40.99.1
|
||||
enabled: true
|
||||
- domain: ap1.emsenhuber.net
|
||||
answer: 10.40.99.11
|
||||
enabled: true
|
||||
- domain: ap2.emsenhuber.net
|
||||
answer: 10.40.99.12
|
||||
enabled: true
|
||||
- domain: branch.emsenhuber.net
|
||||
answer: 10.40.99.2
|
||||
enabled: true
|
||||
- domain: nas.bf.emsenhuber.net
|
||||
answer: 10.40.20.10
|
||||
enabled: true
|
||||
@@ -316,7 +258,232 @@ clients:
|
||||
rdns: true
|
||||
dhcp: true
|
||||
hosts: true
|
||||
persistent: []
|
||||
persistent:
|
||||
- safe_search:
|
||||
enabled: false
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: dns-bypass-exempt
|
||||
ids:
|
||||
- 10.40.10.82
|
||||
- 10.40.10.183
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: 381d431a-1a43-41ea-adaa-2d67ada9aab0
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: false
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
- safe_search:
|
||||
enabled: true
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: grp-guest
|
||||
ids:
|
||||
- 10.40.90.0/24
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: af70dd86-43a9-4165-8228-26c7b90db5e6
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: false
|
||||
filtering_enabled: true
|
||||
parental_enabled: true
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
- safe_search:
|
||||
enabled: false
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: grp-infra
|
||||
ids:
|
||||
- 10.40.20.0/24
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: 78b2da82-1946-41ee-b386-b04eaee49bc3
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: false
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
- safe_search:
|
||||
enabled: false
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: grp-iot
|
||||
ids:
|
||||
- 10.40.30.0/24
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: 7a8ac674-4365-4b06-ad51-2516400903a1
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: true
|
||||
filtering_enabled: true
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
- safe_search:
|
||||
enabled: false
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: grp-main
|
||||
ids:
|
||||
- 10.40.10.0/24
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: 39955cc1-6ec2-4cf6-a757-233672b9dc3d
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: true
|
||||
filtering_enabled: true
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
- safe_search:
|
||||
enabled: false
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: grp-media
|
||||
ids:
|
||||
- 10.40.40.0/24
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: 44e4a1d7-d1b6-446c-a753-65e714ec93aa
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: false
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
- safe_search:
|
||||
enabled: false
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: grp-mgmt
|
||||
ids:
|
||||
- 10.40.99.0/24
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: 4c5eeafb-f7f2-4fb1-ab87-fd2a2366d57a
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: false
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
- safe_search:
|
||||
enabled: false
|
||||
bing: false
|
||||
duckduckgo: false
|
||||
ecosia: false
|
||||
google: false
|
||||
pixabay: false
|
||||
yandex: false
|
||||
youtube: false
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Local
|
||||
ids: []
|
||||
name: grp-untrusted
|
||||
ids:
|
||||
- 10.40.50.0/24
|
||||
tags: []
|
||||
upstreams: []
|
||||
uid: 7f182498-7b82-4580-b1b0-0a2d46c205ef
|
||||
upstreams_cache_size: 0
|
||||
upstreams_cache_enabled: false
|
||||
use_global_settings: true
|
||||
filtering_enabled: true
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: true
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
log:
|
||||
enabled: true
|
||||
file: ""
|
||||
|
||||
57
adguard/README.md
Normal file
57
adguard/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# AdGuard Home — `agh-bf1` (.36) / `agh-bf2` (.37) · TP23 Stufe 2/4/5
|
||||
|
||||
Das AGH-**Paar** (pve LXC 110/111, `10.40.20.36` / `.37`) ist der Client-Resolver des BF-Netzes
|
||||
(DHCP liefert beide in allen 7 VLANs). Upstream: DoH zum CF-Gateway; conditional
|
||||
`[/bf.emsenhuber.net/] → 10.40.20.1`. **Kein natives HA** → Sync ist Betriebsaufwand.
|
||||
|
||||
## Dateien
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `AdGuardHome.yaml` | **Repo-SSoT** der Config. **Passwort-Hashes REDIGIERT** (`'<redacted>'`) — keine Secrets im Git. Echte Hashes leben auf den Geräten; Klartext des API-Users in `~/.secrets`. |
|
||||
| `agh-sync.py` | `check` (Drift `.36`↔`.37`) · `push` (SSoT auf beide, gestaffelter Restart, reinjiziert Hashes live). |
|
||||
| `agh-exception.py` | Exception-Primitive (Stufe 5) gegen **beide** Instanzen. |
|
||||
|
||||
## Client-Policy (Stufe 4, `clients.persistent`)
|
||||
Ein VLAN = eine CIDR-Gruppe. Alle nutzen denselben CF-Upstream-Filter; Divergenz = per-Client-Toggle.
|
||||
|
||||
| Gruppe | CIDR | filtering | safe_search | parental |
|
||||
|---|---|---|---|---|
|
||||
| grp-main | 10.40.10.0/24 | an (global) | – | – |
|
||||
| grp-infra | 10.40.20.0/24 | **aus** | – | – |
|
||||
| grp-iot | 10.40.30.0/24 | an | – | – |
|
||||
| grp-media | 10.40.40.0/24 | **aus** | – | – |
|
||||
| grp-untrusted | 10.40.50.0/24 | an | – | – |
|
||||
| grp-guest | 10.40.90.0/24 | an | **on** | **on** |
|
||||
| grp-mgmt | 10.40.99.0/24 | **aus** | – | – |
|
||||
| dns-bypass-exempt | 10.40.10.183 + .82 | **aus** | – | – |
|
||||
|
||||
`filtering aus` bei INFRA/MEDIA/MGMT = bewusste Reduktion (Streaming/Server/Mgmt nicht brechen), per Gruppe rückholbar.
|
||||
|
||||
## Sync-Invariante
|
||||
AGH **schreibt die YAML beim Restart um** (normalisiert) → **nicht** gegen die Repo-Datei diffen,
|
||||
sondern **`.36` == `.37`**. Genau das prüft `agh-sync.py check`.
|
||||
|
||||
## Exception-Contract (Stufe 5 — was die HA-Schicht auslöst)
|
||||
Auth: Basic, User `automation` (`~/.secrets` → `AGH_AUTOMATION_*`). **Immer auf `.36` UND `.37`.**
|
||||
|
||||
🔴 **Wichtig für D:** die beiden AGH-Endpunkte sind **read-modify-write**, kein simples Append —
|
||||
`set_rules` **ersetzt die ganze Liste**, `clients/update` braucht das **volle Client-Objekt**.
|
||||
Ein zustandsloses HA-`rest_command` reicht deshalb **nicht**; `agh-exception.py` ist die
|
||||
Referenz-RMW-Implementierung, die D aufruft (Deploy-Weg auf HAOS in Etappe D zu entscheiden:
|
||||
`shell_command`/`command_line` gegen die deployte CLI **oder** ein dünner Wrapper-Endpunkt).
|
||||
|
||||
| Aktion | CLI | AGH-API (RMW) |
|
||||
|---|---|---|
|
||||
| Domain global entsperren | `allow-domain <d>` | `GET /control/filtering/status` → +`@@\|\|<d>^` → `POST /control/filtering/set_rules` |
|
||||
| Entsperrung zurück | `unallow-domain <d>` | dito, Regel entfernen |
|
||||
| Client entfiltern | `unfilter <ip>` | `GET /control/clients` → Objekt, `filtering_enabled=false` → `POST /control/clients/update` |
|
||||
| Client wieder filtern | `refilter <ip>` | dito, zurück auf global |
|
||||
|
||||
**Kein Timing in der CLI** — Ablauf/Revert macht der Aufrufer (HA-Timer) und, ab Stufe 6, der
|
||||
RouterOS-Backstop.
|
||||
|
||||
## RouterOS-Backstop (Stufe 6, noch NICHT gebaut)
|
||||
Analog `jit-admin` (`routeros/tp5-etappe4-input-mgmt.rsc`): Address-List `jit-dns-bypass` mit
|
||||
`timeout` + Forward-Regel, die dieser Liste 53/853 nach außen erlaubt — der Fail-safe, falls HA
|
||||
den Revert verpasst. Gebaut via **Nautobot GC** (kein Direkt-Write), erst wenn die Bypass-Sperre
|
||||
scharf geschaltet wird.
|
||||
129
adguard/agh-exception.py
Executable file
129
adguard/agh-exception.py
Executable file
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
agh-exception.py — TP23 Stufe 5 Exception-Primitive gegen das AGH-Paar (.36 + .37).
|
||||
|
||||
Von der HA-Self-Service-Schicht (rest_command) ODER von Hand aufrufbar. Wirkt IMMER auf
|
||||
BEIDE Instanzen (kein Sync im Datenpfad). KEIN eigenes Timing — Ablauf/Revert macht der
|
||||
Aufrufer (HA-Timer) bzw. der RouterOS-Backstop (Stufe 6). Diese CLI ist reines add/remove.
|
||||
|
||||
allow-domain <domain> → user_rules += @@||domain^ (Domain für ALLE entsperren)
|
||||
unallow-domain <domain> → user_rules -= @@||domain^
|
||||
unfilter <ip> → Client (dessen ids <ip> enthält) filtering_enabled=false
|
||||
refilter <ip> → denselben Client wieder filtern (use_global_settings=true)
|
||||
status → user_rules + Client-Policy beider Instanzen
|
||||
|
||||
Auth: AGH_AUTOMATION_USER/_PASS aus ~/.secrets/credentials.env (nie in argv).
|
||||
"""
|
||||
import sys, os, json, base64, urllib.request, urllib.error, pathlib, re
|
||||
|
||||
DOMAIN_RE = re.compile(r"^(?=.{1,253}$)([a-z0-9](-?[a-z0-9]+)*\.)+[a-z]{2,}$", re.I)
|
||||
IP_RE = re.compile(r"^\d{1,3}(\.\d{1,3}){3}$")
|
||||
|
||||
INST = ["10.40.20.36", "10.40.20.37"]
|
||||
# Creds-Quellen in Reihenfolge: erste, die User+Pass liefert, gewinnt.
|
||||
# So läuft derselbe Code auf dem Mac (~/.secrets) und auf HAOS (/config).
|
||||
CRED_FILES = [
|
||||
os.environ.get("AGH_CREDS_FILE"),
|
||||
str(pathlib.Path.home() / ".secrets/credentials.env"),
|
||||
"/config/agh-exception.secrets",
|
||||
]
|
||||
|
||||
|
||||
def _from_file(path):
|
||||
u = p = None
|
||||
try:
|
||||
for line in open(path).read().splitlines():
|
||||
if line.startswith("AGH_AUTOMATION_USER="): u = line.split("=", 1)[1].strip()
|
||||
if line.startswith("AGH_AUTOMATION_PASS="): p = line.split("=", 1)[1].strip()
|
||||
except OSError:
|
||||
return None
|
||||
return (u, p) if (u and p) else None
|
||||
|
||||
|
||||
def creds():
|
||||
eu, ep = os.environ.get("AGH_AUTOMATION_USER"), os.environ.get("AGH_AUTOMATION_PASS")
|
||||
if eu and ep:
|
||||
return eu, ep
|
||||
for f in CRED_FILES:
|
||||
if f and (r := _from_file(f)):
|
||||
return r
|
||||
sys.exit("AGH_AUTOMATION_USER/_PASS: weder Env noch eine Creds-Datei gefunden")
|
||||
|
||||
|
||||
AUTH = "Basic " + base64.b64encode(":".join(creds()).encode()).decode()
|
||||
|
||||
|
||||
def api(ip, path, method="GET", body=None):
|
||||
url = f"http://{ip}{path}"
|
||||
data = json.dumps(body).encode() if body is not None else None
|
||||
req = urllib.request.Request(url, data=data, method=method,
|
||||
headers={"Authorization": AUTH,
|
||||
"Content-Type": "application/json"})
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=8) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
except urllib.error.HTTPError as e:
|
||||
sys.exit(f"{ip} {path} → HTTP {e.code}: {e.read().decode()[:200]}")
|
||||
except Exception as e:
|
||||
sys.exit(f"{ip} {path} → {e}")
|
||||
|
||||
|
||||
def rule(domain):
|
||||
return f"@@||{domain}^"
|
||||
|
||||
|
||||
def allow(domain, remove=False):
|
||||
domain = domain.strip().lower()
|
||||
if not DOMAIN_RE.match(domain):
|
||||
sys.exit(f"ungültige Domain: {domain!r}")
|
||||
r = rule(domain)
|
||||
for ip in INST:
|
||||
st = api(ip, "/control/filtering/status")
|
||||
rules = st.get("user_rules", [])
|
||||
if remove:
|
||||
rules = [x for x in rules if x != r]
|
||||
elif r not in rules:
|
||||
rules = rules + [r]
|
||||
api(ip, "/control/filtering/set_rules", "POST", {"rules": rules})
|
||||
print(f"{ip}: {'entfernt' if remove else 'gesetzt'} {r} (user_rules={len(rules)})")
|
||||
|
||||
|
||||
def set_filter(ip_addr, enabled):
|
||||
if not IP_RE.match(ip_addr):
|
||||
sys.exit(f"ungültige IP: {ip_addr!r}")
|
||||
for ip in INST:
|
||||
data = api(ip, "/control/clients")
|
||||
c = None
|
||||
for cand in data.get("clients", []):
|
||||
if ip_addr in cand.get("ids", []):
|
||||
c = cand; break
|
||||
if not c:
|
||||
sys.exit(f"{ip}: kein Client mit id exakt {ip_addr} — für Gruppen die CIDR angeben")
|
||||
c = dict(c)
|
||||
c["use_global_settings"] = enabled
|
||||
c["filtering_enabled"] = enabled
|
||||
api(ip, "/control/clients/update", "POST", {"name": c["name"], "data": c})
|
||||
print(f"{ip}: {c['name']} filtering={'an' if enabled else 'AUS'}")
|
||||
|
||||
|
||||
def status():
|
||||
for ip in INST:
|
||||
st = api(ip, "/control/filtering/status")
|
||||
allows = [r for r in st.get("user_rules", []) if r.startswith("@@")]
|
||||
cl = api(ip, "/control/clients").get("clients", [])
|
||||
print(f"== {ip} == allow-rules={allows or '—'}")
|
||||
for c in cl:
|
||||
print(f" {c['name']:16} ids={c['ids']} global={c['use_global_settings']} filt={c['filtering_enabled']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
a = sys.argv[1:]
|
||||
if not a: sys.exit(__doc__)
|
||||
cmd = a[0]
|
||||
if cmd == "allow-domain": allow(a[1])
|
||||
elif cmd == "unallow-domain": allow(a[1], remove=True)
|
||||
elif cmd == "unfilter": set_filter(a[1], False)
|
||||
elif cmd == "refilter": set_filter(a[1], True)
|
||||
elif cmd == "status": status()
|
||||
else: sys.exit(f"unbekannt: {cmd}\n{__doc__}")
|
||||
113
adguard/agh-sync.py
Executable file
113
adguard/agh-sync.py
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
agh-sync.py — AdGuard-Home-Paar agh-bf1 (.36) / agh-bf2 (.37) synchron halten.
|
||||
|
||||
TP23 Stufe 2/4: die beiden AGH-Instanzen (pve LXC 110/111) haben KEIN natives HA →
|
||||
Config-Sync ist Betriebsaufwand. Dieses Werkzeug ist der Sync.
|
||||
|
||||
SSoT = adguard/AdGuardHome.yaml (Passwort-Hashes REDIGIERT — keine Secrets im Git).
|
||||
Wahrheit im Datenpfad = die beiden Live-Instanzen; die Invariante ist .36 == .37
|
||||
(AGH normalisiert die YAML beim Restart, daher NICHT gegen die Repo-Datei vergleichen,
|
||||
sondern die beiden Live-Configs gegeneinander).
|
||||
|
||||
check pull .36 + .37, Passwörter redigiert diffen → meldet Drift (exit 1 bei Drift)
|
||||
push Repo-SSoT nehmen, echte users-Hashes aus .36 (live) reinjizieren, validieren,
|
||||
auf beide pushen, GESTAFFELT neu starten (110 → prüfen → 111), .36==.37 + API prüfen
|
||||
|
||||
Kein Direkt-`sshpass -p` (Leak). SSH-Key zu root@pve vorausgesetzt.
|
||||
"""
|
||||
import subprocess, sys, tempfile, base64, os, re, pathlib, urllib.request
|
||||
|
||||
PVE = "root@10.40.20.100"
|
||||
INST = {"110": "10.40.20.36", "111": "10.40.20.37"} # ct-id -> ip
|
||||
PRIMARY = "110" # Reihenfolge: primary zuerst
|
||||
SVC = "AdGuardHome.service"
|
||||
CFG = "/opt/AdGuardHome/AdGuardHome.yaml"
|
||||
REPO = pathlib.Path(__file__).resolve().parent
|
||||
SSOT = REPO / "AdGuardHome.yaml"
|
||||
PW_RE = re.compile(r"^( password: ).*$")
|
||||
|
||||
|
||||
def sh(*args, inp=None):
|
||||
return subprocess.run(args, input=inp, capture_output=True, text=True)
|
||||
|
||||
|
||||
def pull(ct):
|
||||
r = sh("ssh", "-o", "ConnectTimeout=8", PVE, f"pct exec {ct} -- cat {CFG}")
|
||||
if r.returncode:
|
||||
sys.exit(f"pull {ct} fehlgeschlagen: {r.stderr.strip()}")
|
||||
return r.stdout
|
||||
|
||||
|
||||
def redact(text):
|
||||
return "\n".join(PW_RE.sub(r"\1'<redacted>'", l) for l in text.splitlines())
|
||||
|
||||
|
||||
def live_users_hashes(ct):
|
||||
"""echte password-Zeilen (in Reihenfolge) aus der Live-Config von ct."""
|
||||
out, inusers = [], False
|
||||
for l in pull(ct).splitlines():
|
||||
if l.startswith("users:"): inusers = True; continue
|
||||
if inusers and l and not l.startswith((" ", "\t")): break
|
||||
if inusers:
|
||||
m = PW_RE.match(l)
|
||||
if m: out.append(l)
|
||||
return out
|
||||
|
||||
|
||||
def cmd_check():
|
||||
a, b = redact(pull("110")), redact(pull("111"))
|
||||
if a == b:
|
||||
print("✅ .36 == .37 (synchron)")
|
||||
return 0
|
||||
print("🔴 DRIFT zwischen .36 und .37:")
|
||||
import difflib
|
||||
for line in difflib.unified_diff(a.splitlines(), b.splitlines(),
|
||||
".36", ".37", lineterm=""):
|
||||
print(line)
|
||||
return 1
|
||||
|
||||
|
||||
def cmd_push():
|
||||
if not SSOT.exists():
|
||||
sys.exit(f"SSoT fehlt: {SSOT}")
|
||||
ssot = SSOT.read_text()
|
||||
# echte Hashes aus dem primary reinjizieren (SSoT trägt nur Redaktions-Platzhalter)
|
||||
hashes = live_users_hashes(PRIMARY)
|
||||
red = [i for i, l in enumerate(ssot.splitlines()) if PW_RE.match(l)]
|
||||
if len(red) != len(hashes):
|
||||
sys.exit(f"users-Anzahl SSoT({len(red)}) != live({len(hashes)}) — manuell prüfen")
|
||||
lines = ssot.splitlines()
|
||||
for idx, real in zip(red, hashes):
|
||||
lines[idx] = real
|
||||
merged = "\n".join(lines) + "\n"
|
||||
# validieren
|
||||
try:
|
||||
import yaml
|
||||
doc = yaml.safe_load(merged)
|
||||
assert doc["users"] and doc["clients"]["persistent"]
|
||||
except Exception as e:
|
||||
sys.exit(f"merge invalide: {e}")
|
||||
b64 = base64.b64encode(merged.encode()).decode()
|
||||
order = [PRIMARY] + [c for c in INST if c != PRIMARY]
|
||||
for ct in order:
|
||||
print(f"→ push + restart {ct} ({INST[ct]}) …")
|
||||
r = sh("ssh", "-o", "ConnectTimeout=10", PVE,
|
||||
f"pct exec {ct} -- sh -c 'base64 -d > {CFG}.new && "
|
||||
f"cp -a {CFG} {CFG}.presync && mv {CFG}.new {CFG} && "
|
||||
f"systemctl restart {SVC} && sleep 2 && systemctl is-active {SVC}'",
|
||||
inp=b64)
|
||||
if r.returncode or "active" not in r.stdout:
|
||||
sys.exit(f"push {ct} fehlgeschlagen: {r.stdout} {r.stderr}")
|
||||
print(f" {ct} active")
|
||||
print(cmd_check_msg())
|
||||
return cmd_check()
|
||||
|
||||
|
||||
def cmd_check_msg():
|
||||
return "— Verifikation:"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cmd = sys.argv[1] if len(sys.argv) > 1 else "check"
|
||||
sys.exit({"check": cmd_check, "push": cmd_push}.get(cmd, cmd_check)())
|
||||
63
adguard/ha-self-service.md
Normal file
63
adguard/ha-self-service.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# TP23 Stufe 5 — HA-Self-Service für DNS-Ausnahmen
|
||||
|
||||
Home Assistant (HAOS-VM 100, `10.40.20.105`) gibt eine Ein-Klick-Oberfläche, um eine Domain
|
||||
temporär (JIT) über das AGH-Paar `.36`/`.37` zu entsperren. Ablauf/Revert nativ per `timer`.
|
||||
|
||||
**Warum kein `rest_command`:** die AGH-Endpunkte sind read-modify-write (`set_rules` ersetzt die
|
||||
ganze Liste). HA ruft deshalb die deployte RMW-CLI `agh-exception.py` per `shell_command`.
|
||||
|
||||
## Bausteine (alle in HA .storage, via ha-mcp angelegt — keine YAML außer shell_command)
|
||||
| Typ | entity_id | Zweck |
|
||||
|---|---|---|
|
||||
| input_text | `input_text.dns_ausnahme_domain` | einzugebende Domain |
|
||||
| input_text | `input_text.dns_ausnahme_aktiv` | aktuell aktive Ausnahme (für leak-freien Revert; init `""`) |
|
||||
| input_select | `input_select.dns_ausnahme_dauer` | 15 Minuten / 1 Stunde / 4 Stunden |
|
||||
| timer | `timer.dns_ausnahme` | JIT-Countdown (restore=false) |
|
||||
| input_button | `input_button.dns_ausnahme_starten` | Auslöser |
|
||||
| automation | `automation.dns_ausnahme_starten` | Button → validieren, alte Ausnahme aufräumen, `agh_allow_domain`, Timer starten |
|
||||
| automation | `automation.dns_ausnahme_ablauf` | `timer.finished`/`timer.cancelled` → `agh_unallow_domain`, `_aktiv` leeren |
|
||||
|
||||
## `configuration.yaml` (der einzige YAML-Teil, Backup `.bak-tp23-*`)
|
||||
```yaml
|
||||
shell_command:
|
||||
agh_allow_domain: "python3 /config/agh-exception.py allow-domain '{{ domain }}'"
|
||||
agh_unallow_domain: "python3 /config/agh-exception.py unallow-domain '{{ domain }}'"
|
||||
agh_unfilter_client: "python3 /config/agh-exception.py unfilter '{{ ip }}'"
|
||||
agh_refilter_client: "python3 /config/agh-exception.py refilter '{{ ip }}'"
|
||||
```
|
||||
Neue Domain → **HA-Neustart** nötig (reload_all lädt eine erstmals hinzugefügte Domain nicht).
|
||||
|
||||
## Deploy auf HAOS (Zugang `ssh admin@10.40.20.105`, sudo passwortlos)
|
||||
- `/config/agh-exception.py` — Kopie von `adguard/agh-exception.py` (liest Creds via `/config/agh-exception.secrets`).
|
||||
- `/config/agh-exception.secrets` (chmod 600, root) — `AGH_AUTOMATION_USER`/`_PASS`.
|
||||
- Redeploy nach Script-Änderung: `base64 < adguard/agh-exception.py | ssh admin@10.40.20.105 "base64 -d | sudo tee /config/agh-exception.py >/dev/null"`.
|
||||
|
||||
## Bedienung
|
||||
Domain eintragen → Dauer wählen → **DNS-Ausnahme starten**. Bei Ablauf/Abbruch wird die Regel auf
|
||||
beiden AGH automatisch zurückgenommen. Ungültige Domains werden HA- **und** CLI-seitig abgelehnt.
|
||||
|
||||
## Dashboard (1. Draft, 2026-09-06)
|
||||
Eigenes storage-mode Dashboard `url_path: dns-ausnahmen` (Sidebar, `require_admin: false`),
|
||||
angelegt via `ha_config_set_dashboard`. Da es in HA-`.storage` lebt, hier die Repro-Quelle:
|
||||
```json
|
||||
{"views":[{"title":"DNS-Ausnahmen","path":"dns","type":"sections","icon":"mdi:dns","max_columns":2,"sections":[
|
||||
{"type":"grid","cards":[
|
||||
{"type":"heading","heading":"Domain temporaer freigeben","icon":"mdi:lock-open-variant"},
|
||||
{"type":"entities","entities":[{"entity":"input_text.dns_ausnahme_domain","name":"Domain"},{"entity":"input_select.dns_ausnahme_dauer","name":"Dauer"}]},
|
||||
{"type":"button","name":"DNS-Ausnahme starten","icon":"mdi:lock-open-check","tap_action":{"action":"perform-action","perform_action":"input_button.press","target":{"entity_id":"input_button.dns_ausnahme_starten"}},"grid_options":{"columns":"full"}}]},
|
||||
{"type":"grid","cards":[
|
||||
{"type":"heading","heading":"Status","icon":"mdi:information-outline"},
|
||||
{"type":"tile","entity":"timer.dns_ausnahme","name":"Restlaufzeit"},
|
||||
{"type":"tile","entity":"input_text.dns_ausnahme_aktiv","name":"Aktive Ausnahme"},
|
||||
{"type":"markdown","content":"**AGH-Resolver-Paar** — .36: {{ states('binary_sensor.adguard_bf1_status') }} / .37: {{ states('binary_sensor.adguard_bf2_status') }}"}]},
|
||||
{"type":"grid","cards":[
|
||||
{"type":"heading","heading":"VLAN-Filter-Policy (AGH-Gruppen)","heading_style":"subtitle"},
|
||||
{"type":"markdown","content":"MAIN/IOT/UNTRUSTED=an · INFRA/MEDIA/MGMT=aus · GUEST=an+SafeSearch/Parental · dns-bypass-exempt=aus"}]}
|
||||
]}]}
|
||||
```
|
||||
⚠️ Draft-Notiz: `binary_sensor.adguard_bf1_status` ist stale (hing am alten `.16`-Container, TP42) —
|
||||
zeigt evtl. `unavailable`, obwohl `.36` läuft. Sensor-Quelle gehört bei Gelegenheit auf `.36` gefixt.
|
||||
|
||||
## Verifiziert (2026-09-04)
|
||||
Button → `@@||doubleclick.net^` auf `.36`+`.37`, Timer 15:00, `_aktiv` gesetzt; Timer-Abbruch →
|
||||
Regel auf beiden entfernt, `_aktiv` geleert, `.36==.37`.
|
||||
218
bin/gitea-tp-sync.py
Normal file
218
bin/gitea-tp-sync.py
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
TP36 (reframed) — teilprojekte.md Index/Status → Gitea Issues (admin/bf-infra).
|
||||
|
||||
Idempotenter Sync (get-or-create, Match ueber "TPnn" im Titel):
|
||||
- Archiv-Header in docs/teilprojekte-archiv.md -> closed Issues (nur TPs, die in Gitea
|
||||
NICHT offen sind; ein reopentes TP mit Archiv-Zeiger bleibt offen).
|
||||
- Labels status:* (Marker) + thema:* (Gruppierung) werden vorab get-or-create.
|
||||
|
||||
SSoT-Modell (seit TP36-Cutover 2026-09-07): Gitea fuehrt Index+Status — aktive TPs werden
|
||||
DIREKT als Gitea-Issue angelegt/gepflegt, NICHT mehr aus einer Datei-Tabelle abgeleitet
|
||||
(die Quick-Index-Tabelle wurde aus teilprojekte.md entfernt). Dieses Werkzeug haelt nur noch
|
||||
die ARCHIVIERTEN (closed) TPs mit teilprojekte-archiv.md idempotent abgeglichen und fasst
|
||||
offene Issues nie an. Die per-TP-Prosa bleibt in docs/teilprojekte.md / teilprojekte-archiv.md.
|
||||
Token: ~/.hermes/.env (GITEA_ACCESS_TOKEN, GITEA_HOST) — wird NIE ausgegeben.
|
||||
|
||||
Aufruf:
|
||||
python3 bin/gitea-tp-sync.py # Dry-Run (default) — zeigt, was passieren wuerde
|
||||
python3 bin/gitea-tp-sync.py --commit # legt Labels + Issues an / gleicht sie ab
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
ACTIVE = REPO / "docs" / "teilprojekte.md"
|
||||
ARCHIV = REPO / "docs" / "teilprojekte-archiv.md"
|
||||
HERMES = Path.home() / ".hermes" / ".env"
|
||||
OWNER_REPO = "admin/bf-infra"
|
||||
COMMIT = "--commit" in sys.argv
|
||||
|
||||
# Marker -> (status-label, gitea-state)
|
||||
MARKER = {
|
||||
"🔜": ("status:todo", "open"),
|
||||
"⏳": ("status:wip", "open"),
|
||||
"⏸️": ("status:paused", "open"),
|
||||
"💡": ("status:idea", "open"),
|
||||
"🟢": ("status:concept", "open"),
|
||||
"✅": ("status:done", "closed"),
|
||||
"❌": ("status:dropped", "closed"),
|
||||
}
|
||||
LABEL_COLORS = {
|
||||
"status:todo": "#ededed", "status:wip": "#fbca04", "status:paused": "#c5def5",
|
||||
"status:idea": "#d4c5f9", "status:concept": "#bfdadc", "status:done": "#0e8a16",
|
||||
"status:dropped": "#e11d21",
|
||||
"thema:firewall-dns": "#b60205", "thema:wlan": "#1d76db", "thema:cloudflare-proxy": "#f9a825",
|
||||
"thema:nautobot-doku": "#5319e7", "thema:infra": "#0e8a16", "thema:ipv6-matter": "#006b75",
|
||||
"thema:identity": "#e99695", "thema:backlog": "#cccccc",
|
||||
}
|
||||
# TP-Nummer -> Themen-Label (aus dem Statusbaum-Gruppierung; nur aktive TPs brauchen ein Board-Thema)
|
||||
THEME = {
|
||||
"5.1": "firewall-dns", "23": "firewall-dns",
|
||||
"25": "wlan", "28": "wlan", "13": "wlan", "17.1": "wlan", "17.3": "wlan",
|
||||
"16": "cloudflare-proxy", "16.2": "cloudflare-proxy", "16.3": "cloudflare-proxy",
|
||||
"31": "cloudflare-proxy", "41": "cloudflare-proxy", "14.4": "cloudflare-proxy",
|
||||
"42": "cloudflare-proxy", "43": "cloudflare-proxy", "44": "cloudflare-proxy",
|
||||
"32": "nautobot-doku", "34": "nautobot-doku", "35": "nautobot-doku",
|
||||
"36": "nautobot-doku", "37": "nautobot-doku",
|
||||
"30": "infra", "40": "infra", "20.1": "infra", "18": "infra",
|
||||
"24": "infra", "38": "infra", "11": "infra",
|
||||
"12": "ipv6-matter", "12.1": "ipv6-matter",
|
||||
"8": "identity",
|
||||
"29": "backlog", "33": "backlog",
|
||||
}
|
||||
|
||||
|
||||
def hermes_env():
|
||||
tok = host = None
|
||||
for line in HERMES.read_text().splitlines():
|
||||
m = re.match(r"\s*(GITEA_ACCESS_TOKEN|GITEA_HOST)\s*=\s*(.+?)\s*$", line)
|
||||
if not m:
|
||||
continue
|
||||
if m.group(1) == "GITEA_ACCESS_TOKEN":
|
||||
tok = m.group(2).strip().strip('"').strip("'")
|
||||
else:
|
||||
host = m.group(2).strip().strip('"').strip("'")
|
||||
if not tok:
|
||||
sys.exit("GITEA_ACCESS_TOKEN nicht in %s gefunden." % HERMES)
|
||||
host = (host or "https://gitea.emsenhuber.net").rstrip("/")
|
||||
if not host.startswith("http"):
|
||||
host = "https://" + host
|
||||
return tok, host
|
||||
|
||||
|
||||
TOKEN, HOST = hermes_env()
|
||||
API = HOST + "/api/v1"
|
||||
|
||||
|
||||
def api(method, path, body=None):
|
||||
url = API + path
|
||||
data = json.dumps(body).encode() if body is not None else None
|
||||
req = urllib.request.Request(url, data=data, method=method, headers={
|
||||
"Authorization": "token " + TOKEN,
|
||||
"Accept": "application/json", "Content-Type": "application/json"})
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
return r.status, json.load(r)
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, (json.load(e) if e.headers.get("content-type", "").startswith("application/json") else {})
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- parse
|
||||
def parse_archiv(exclude_nums):
|
||||
"""Archiv-Header -> archivierte TPs. exclude_nums = TP-Nummern, die in Gitea OFFEN sind
|
||||
(reopente TPs mit Archiv-Zeiger) -> die bleiben offen, nicht als closed abgleichen."""
|
||||
out = []
|
||||
hdr = re.compile(r"^#{2,4}\s*(TP[\d.\-A-Za-z]+)\s*—\s*(.+?)\s*▸", )
|
||||
seen = set()
|
||||
for line in ARCHIV.read_text().splitlines():
|
||||
m = hdr.match(line)
|
||||
if not m:
|
||||
continue
|
||||
tp, title = m.groups()
|
||||
num = tp[2:]
|
||||
if num in exclude_nums or num in seen:
|
||||
continue
|
||||
seen.add(num)
|
||||
short = re.sub(r"\*\*|`", "", title).strip()[:80]
|
||||
out.append({"tp": tp, "num": num, "marker": "✅",
|
||||
"title": short, "date": "", "src": "archiv"})
|
||||
return out
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- gitea sync
|
||||
def ensure_labels(existing):
|
||||
by_name = {l["name"]: l for l in existing}
|
||||
for name, color in LABEL_COLORS.items():
|
||||
if name in by_name:
|
||||
continue
|
||||
if COMMIT:
|
||||
api("POST", f"/repos/{OWNER_REPO}/labels",
|
||||
{"name": name, "color": color.lstrip("#")})
|
||||
print(f" [{'+' if COMMIT else 'DRY'}] label {name}")
|
||||
st, cur = api("GET", f"/repos/{OWNER_REPO}/labels?limit=100")
|
||||
return {l["name"]: l["id"] for l in (cur if isinstance(cur, list) else [])}
|
||||
|
||||
|
||||
def all_issues():
|
||||
out, page = [], 1
|
||||
while True:
|
||||
st, d = api("GET", f"/repos/{OWNER_REPO}/issues?state=all&type=issues&limit=50&page={page}")
|
||||
if not isinstance(d, list) or not d:
|
||||
break
|
||||
out += d
|
||||
page += 1
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
print(f"Gitea {HOST} repo {OWNER_REPO} mode={'COMMIT' if COMMIT else 'DRY-RUN'}")
|
||||
|
||||
st, existing_labels = api("GET", f"/repos/{OWNER_REPO}/labels?limit=100")
|
||||
label_id = ensure_labels(existing_labels if isinstance(existing_labels, list) else [])
|
||||
|
||||
issues = all_issues()
|
||||
by_tp = {}
|
||||
open_nums = set()
|
||||
for iss in issues:
|
||||
# Titel ist "TPxx — …"; volle ID inkl. Buchstaben/Bindestrich (TP14.2a, TP-R) bis zum " — "
|
||||
m = re.match(r"^(TP[\w.\-]*?)\s+—", iss["title"])
|
||||
if m:
|
||||
by_tp[m.group(1)] = iss
|
||||
if iss.get("state") == "open":
|
||||
open_nums.add(m.group(1)[2:])
|
||||
|
||||
# Aktive TPs sind seit dem TP36-Cutover SSoT direkt in Gitea -> nur das Archiv abgleichen,
|
||||
# und offene (reopente) TPs davon ausschliessen, damit sie nicht faelschlich geschlossen werden.
|
||||
items = parse_archiv(open_nums)
|
||||
print(f"Geparst: {len(items)} archivierte TP (aktive TPs = SSoT in Gitea: "
|
||||
f"{len(open_nums)} offen, nicht angetastet)\n")
|
||||
|
||||
created = updated = 0
|
||||
for it in items:
|
||||
status_label, state = MARKER.get(it["marker"], ("status:todo", "open"))
|
||||
labels = [status_label]
|
||||
th = THEME.get(it["num"])
|
||||
if th:
|
||||
labels.append(f"thema:{th}")
|
||||
title = f"{it['tp']} — {it['title']}"
|
||||
body = (f"Steuerungs-SSoT: Index/Status hier in Gitea; **Prosa/Detail** im Repo unter "
|
||||
f"`docs/{'teilprojekte-archiv.md' if it['src']=='archiv' else 'teilprojekte.md'}` "
|
||||
f"(Abschnitt `{it['tp']}`).\n\n"
|
||||
f"- Status: {it['marker']} ({status_label})\n"
|
||||
+ (f"- Abschluss: {it['date']}\n" if it["date"] else ""))
|
||||
want_ids = [label_id[l] for l in labels if l in label_id]
|
||||
|
||||
cur = by_tp.get(it["tp"])
|
||||
if cur is None:
|
||||
print(f" [{'+' if COMMIT else 'DRY'}] NEW {title} {labels} state={state}")
|
||||
if COMMIT:
|
||||
sc, res = api("POST", f"/repos/{OWNER_REPO}/issues",
|
||||
{"title": title, "body": body, "labels": want_ids})
|
||||
if state == "closed" and isinstance(res, dict) and res.get("number"):
|
||||
api("PATCH", f"/repos/{OWNER_REPO}/issues/{res['number']}", {"state": "closed"})
|
||||
created += 1
|
||||
else:
|
||||
have = {l["name"] for l in cur.get("labels", [])}
|
||||
drift = (have != set(labels)) or (cur.get("state") != state)
|
||||
if drift:
|
||||
print(f" [{'~' if COMMIT else 'DRY'}] UPD #{cur['number']} {title} "
|
||||
f"{sorted(have)}->{labels} state {cur.get('state')}->{state}")
|
||||
if COMMIT:
|
||||
api("PATCH", f"/repos/{OWNER_REPO}/issues/{cur['number']}",
|
||||
{"labels": want_ids, "state": state})
|
||||
updated += 1
|
||||
|
||||
print(f"\n{'Angelegt' if COMMIT else 'Wuerde anlegen'}: {created} · "
|
||||
f"{'Abgeglichen' if COMMIT else 'Wuerde abgleichen'}: {updated}")
|
||||
if not COMMIT:
|
||||
print("Dry-Run — nichts geschrieben. Mit --commit ausfuehren.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -21,6 +21,13 @@
|
||||
# OEFFENTLICH (via Cloudflare Tunnel + Access; Clients ohne WARP)
|
||||
# =========================================================================
|
||||
vw.emsenhuber.net {
|
||||
# TP41 T2: /admin nur lokal/WARP-intern (kein CF-Header). Via CF (Header CF-Connecting-IP
|
||||
# gesetzt) -> 404 statt Vault-Admin. Ersetzt die frühere WAF-Edge-Regel (403).
|
||||
@cf_admin {
|
||||
header CF-Connecting-IP *
|
||||
path /admin /admin/*
|
||||
}
|
||||
respond @cf_admin 404
|
||||
reverse_proxy http://10.40.20.127
|
||||
}
|
||||
|
||||
@@ -39,7 +46,7 @@ gitea.emsenhuber.net {
|
||||
# =========================================================================
|
||||
# INTERN (Mesh/LAN; Split-Horizon zeigt diese Namen auf 10.40.20.40)
|
||||
# =========================================================================
|
||||
nautobot.emsenhuber.net, nautobot.bf.emsenhuber.net {
|
||||
nautobot.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.30:8080
|
||||
}
|
||||
|
||||
@@ -51,49 +58,49 @@ ds-bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.10:8080
|
||||
}
|
||||
|
||||
ccu.emsenhuber.net, ccu.bf.emsenhuber.net {
|
||||
ccu.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.232
|
||||
}
|
||||
|
||||
iobroker.emsenhuber.net, iobroker.bf.emsenhuber.net {
|
||||
iobroker.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.107:8081
|
||||
}
|
||||
|
||||
z2m25.emsenhuber.net, z2m25.bf.emsenhuber.net {
|
||||
z2m25.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.106:8080
|
||||
}
|
||||
|
||||
# --- MCP-Endpunkte: heute spricht ~/.claude.json diese IPs roh --------------
|
||||
pve-mcp.emsenhuber.net, pve-mcp.bf.emsenhuber.net {
|
||||
pve-mcp.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.173:3000
|
||||
}
|
||||
|
||||
ha-mcp.emsenhuber.net, ha-mcp.bf.emsenhuber.net {
|
||||
ha-mcp.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.105:9583
|
||||
}
|
||||
|
||||
n8n-mcp.emsenhuber.net, n8n-mcp.bf.emsenhuber.net {
|
||||
n8n-mcp.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.167:3001
|
||||
}
|
||||
|
||||
gitea-mcp.emsenhuber.net, gitea-mcp.bf.emsenhuber.net {
|
||||
gitea-mcp.bf.emsenhuber.net {
|
||||
reverse_proxy http://10.40.20.167:3000
|
||||
}
|
||||
|
||||
# --- HTTPS-Backends (Selbstsignat) -----------------------------------------
|
||||
pve.emsenhuber.net, pve.bf.emsenhuber.net {
|
||||
pve.bf.emsenhuber.net {
|
||||
reverse_proxy https://10.40.20.100:8006 {
|
||||
import selfsigned
|
||||
}
|
||||
}
|
||||
|
||||
portainer.emsenhuber.net, portainer.bf.emsenhuber.net {
|
||||
portainer.bf.emsenhuber.net {
|
||||
reverse_proxy https://10.40.20.126:9443 {
|
||||
import selfsigned
|
||||
}
|
||||
}
|
||||
|
||||
pbs.emsenhuber.net, pbs.bf.emsenhuber.net {
|
||||
pbs.bf.emsenhuber.net {
|
||||
reverse_proxy https://10.40.20.135:8007 {
|
||||
import selfsigned
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ def main():
|
||||
continue
|
||||
if host not in caddy:
|
||||
drift.append(f"NUR-CF {host:<32} {tun}: {svc} (in Caddy nicht vorhanden)")
|
||||
elif not svc.startswith(f"http://{CADDY_IP}"):
|
||||
elif not (svc.startswith(f"http://{CADDY_IP}") or svc.startswith(f"https://{CADDY_IP}")):
|
||||
drift.append(f"ABWEICHEND {host:<32} CF={svc} (zeigt nicht auf Caddy {CADDY_IP})")
|
||||
# Caddy-Sites ohne CF-Ingress: nur die suffixlosen Namen sind potenziell Drift.
|
||||
# *.bf.*-Namen sind bewusst intern (Split-Horizon) und brauchen keinen Ingress.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"success":true,"errors":[],"messages":[],"result":{"tunnel_id":"48d3b0b6-7233-4781-a76a-1de4a5e957ce","version":3,"config":{"ingress":[{"service":"https://10.40.20.40:443","hostname":"vw.emsenhuber.net","originRequest":{"originServerName":"vw.emsenhuber.net"}},{"service":"https://10.40.20.40:443","hostname":"hass.emsenhuber.net","originRequest":{"originServerName":"hass.emsenhuber.net"}},{"service":"https://10.40.20.40:443","hostname":"n8n.emsenhuber.net","originRequest":{"originServerName":"n8n.emsenhuber.net"}},{"service":"https://10.40.20.40:443","hostname":"gitea.emsenhuber.net","originRequest":{"originServerName":"gitea.emsenhuber.net"}},{"service":"http_status:404"}],"warp-routing":{"enabled":false}},"source":"cloudflare","created_at":"2026-08-31T05:56:47.739644Z"}}
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
},
|
||||
{
|
||||
"created_at": "2026-05-09T06:45:22Z",
|
||||
"decision": "non_identity",
|
||||
"exclude": [],
|
||||
"id": "5165d139-8733-4d31-a3a5-f6f1d0fd8643",
|
||||
"include": [
|
||||
{
|
||||
"ip": {
|
||||
"ip": "90.146.33.177/32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "bf4",
|
||||
"require": [],
|
||||
"uid": "5165d139-8733-4d31-a3a5-f6f1d0fd8643",
|
||||
"updated_at": "2026-08-07T21:36:42Z",
|
||||
"reusable": true,
|
||||
"precedence": 2
|
||||
},
|
||||
{
|
||||
"created_at": "2026-05-15T13:11:36Z",
|
||||
"decision": "non_identity",
|
||||
"exclude": [],
|
||||
"id": "39fe0e9d-6f63-414d-9d6d-440a7a151f5d",
|
||||
"include": [
|
||||
{
|
||||
"service_token": {
|
||||
"token_id": "65f1821a-f134-4e20-aa66-baf31daddbed"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "claude-mcp",
|
||||
"require": [],
|
||||
"uid": "39fe0e9d-6f63-414d-9d6d-440a7a151f5d",
|
||||
"updated_at": "2026-07-31T15:44:48Z",
|
||||
"reusable": true,
|
||||
"precedence": 3
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": [],
|
||||
"result_info": {
|
||||
"page": 1,
|
||||
"per_page": 200,
|
||||
"count": 3,
|
||||
"total_count": 3,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"result": {
|
||||
"id": "16aaec78-5951-4cf3-aad5-79f63163b5ea",
|
||||
"uid": "16aaec78-5951-4cf3-aad5-79f63163b5ea",
|
||||
"type": "self_hosted",
|
||||
"name": "*.emsenhuber.net",
|
||||
"aud": "d5bb8c4852895834a0010d6f63882f140cf27faf41f94374532c1f013a15c02d",
|
||||
"created_at": "2026-05-05T11:44:38Z",
|
||||
"updated_at": "2026-05-15T13:30:13Z",
|
||||
"domain": "*.emsenhuber.net",
|
||||
"self_hosted_domains": [
|
||||
"*.emsenhuber.net"
|
||||
],
|
||||
"destinations": [
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "*.emsenhuber.net"
|
||||
}
|
||||
],
|
||||
"app_launcher_visible": true,
|
||||
"allowed_idps": [],
|
||||
"tags": [],
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
},
|
||||
{
|
||||
"created_at": "2026-05-09T06:45:22Z",
|
||||
"decision": "non_identity",
|
||||
"exclude": [],
|
||||
"id": "5165d139-8733-4d31-a3a5-f6f1d0fd8643",
|
||||
"include": [
|
||||
{
|
||||
"ip": {
|
||||
"ip": "90.146.33.177/32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "bf4",
|
||||
"require": [],
|
||||
"uid": "5165d139-8733-4d31-a3a5-f6f1d0fd8643",
|
||||
"updated_at": "2026-08-07T21:36:42Z",
|
||||
"reusable": true,
|
||||
"precedence": 2
|
||||
},
|
||||
{
|
||||
"created_at": "2026-05-15T13:11:36Z",
|
||||
"decision": "non_identity",
|
||||
"exclude": [],
|
||||
"id": "39fe0e9d-6f63-414d-9d6d-440a7a151f5d",
|
||||
"include": [
|
||||
{
|
||||
"service_token": {
|
||||
"token_id": "65f1821a-f134-4e20-aa66-baf31daddbed"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "claude-mcp",
|
||||
"require": [],
|
||||
"uid": "39fe0e9d-6f63-414d-9d6d-440a7a151f5d",
|
||||
"updated_at": "2026-07-31T15:44:48Z",
|
||||
"reusable": true,
|
||||
"precedence": 3
|
||||
}
|
||||
],
|
||||
"session_duration": "24h",
|
||||
"enable_binding_cookie": false,
|
||||
"http_only_cookie_attribute": false,
|
||||
"options_preflight_bypass": false,
|
||||
"oauth_configuration": {
|
||||
"enabled": false,
|
||||
"dynamic_client_registration": {
|
||||
"enabled": true,
|
||||
"allowed_uris": [
|
||||
"https://ha-mcp.emsenhuber.net"
|
||||
],
|
||||
"allow_any_on_localhost": true,
|
||||
"allow_any_on_loopback": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"created_at": "2026-06-13T08:34:00Z",
|
||||
"decision": "bypass",
|
||||
"exclude": [],
|
||||
"id": "a8129e37-d3c2-456d-8630-3c6a3449d3f2",
|
||||
"include": [
|
||||
{
|
||||
"everyone": {}
|
||||
}
|
||||
],
|
||||
"name": "bypass",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"uid": "a8129e37-d3c2-456d-8630-3c6a3449d3f2",
|
||||
"updated_at": "2026-06-13T08:48:05Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": [],
|
||||
"result_info": {
|
||||
"page": 1,
|
||||
"per_page": 200,
|
||||
"count": 1,
|
||||
"total_count": 1,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"result": {
|
||||
"id": "1dbc45ca-1376-4a0d-b608-69db58f1875c",
|
||||
"uid": "1dbc45ca-1376-4a0d-b608-69db58f1875c",
|
||||
"type": "self_hosted",
|
||||
"name": "hass, vw, gitea",
|
||||
"aud": "817b2b82d2b1aa9c12de854c7bce9f608b33721f0827cfded68bdc7c5eb92a46",
|
||||
"created_at": "2026-06-13T08:32:39Z",
|
||||
"updated_at": "2026-07-12T12:43:25Z",
|
||||
"domain": "vw.emsenhuber.net",
|
||||
"self_hosted_domains": [
|
||||
"vw.emsenhuber.net",
|
||||
"hass.emsenhuber.net",
|
||||
"gitea.emsenhuber.net"
|
||||
],
|
||||
"destinations": [
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "vw.emsenhuber.net"
|
||||
},
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "hass.emsenhuber.net"
|
||||
},
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "gitea.emsenhuber.net"
|
||||
}
|
||||
],
|
||||
"app_launcher_visible": true,
|
||||
"allowed_idps": [],
|
||||
"tags": [],
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-06-13T08:34:00Z",
|
||||
"decision": "bypass",
|
||||
"exclude": [],
|
||||
"id": "a8129e37-d3c2-456d-8630-3c6a3449d3f2",
|
||||
"include": [
|
||||
{
|
||||
"everyone": {}
|
||||
}
|
||||
],
|
||||
"name": "bypass",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"uid": "a8129e37-d3c2-456d-8630-3c6a3449d3f2",
|
||||
"updated_at": "2026-06-13T08:48:05Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"session_duration": "24h",
|
||||
"enable_binding_cookie": false,
|
||||
"http_only_cookie_attribute": true,
|
||||
"options_preflight_bypass": false
|
||||
},
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": [],
|
||||
"result_info": {
|
||||
"page": 1,
|
||||
"per_page": 200,
|
||||
"count": 1,
|
||||
"total_count": 1,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"result": {
|
||||
"id": "6c32fe23-24d8-433f-b00b-0a3d1558bb30",
|
||||
"uid": "6c32fe23-24d8-433f-b00b-0a3d1558bb30",
|
||||
"type": "warp",
|
||||
"name": "Warp Login App",
|
||||
"aud": "fdfaa967d4118469dc994257f65831caa0162d6c45a14b5205af45e1aeca723b",
|
||||
"created_at": "2026-06-04T18:48:59Z",
|
||||
"updated_at": "2026-06-06T16:53:32Z",
|
||||
"domain": "emsenhuber.cloudflareaccess.com/warp",
|
||||
"allowed_idps": [],
|
||||
"session_duration": "24h",
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"tags": []
|
||||
},
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": [],
|
||||
"result_info": {
|
||||
"page": 1,
|
||||
"per_page": 200,
|
||||
"count": 1,
|
||||
"total_count": 1,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"result": {
|
||||
"id": "6df5c431-adcf-4dde-805d-4eb22d7c19b4",
|
||||
"uid": "6df5c431-adcf-4dde-805d-4eb22d7c19b4",
|
||||
"type": "app_launcher",
|
||||
"name": "App Launcher",
|
||||
"aud": "015e805251579e50a49668775c2255facb5bc56007ce49f90885f4114584bae2",
|
||||
"created_at": "2026-03-28T16:20:27Z",
|
||||
"updated_at": "2026-07-08T11:56:56Z",
|
||||
"domain": "emsenhuber.cloudflareaccess.com",
|
||||
"allowed_idps": [],
|
||||
"session_duration": "730h",
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"landing_page_design": {},
|
||||
"skip_app_launcher_login_page": false
|
||||
},
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": []
|
||||
}
|
||||
449
docs/cf-backup/tp41-20260901/apps-all.json
Normal file
449
docs/cf-backup/tp41-20260901/apps-all.json
Normal file
@@ -0,0 +1,449 @@
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"id": "86287661-7b23-4f38-874c-926cab1c0535",
|
||||
"uid": "86287661-7b23-4f38-874c-926cab1c0535",
|
||||
"type": "self_hosted",
|
||||
"name": "Terpenfinder v3 assetlinks",
|
||||
"aud": "353385474c9665c498f2c2477b0236a14a363aff5a700017ee5def5792587c62",
|
||||
"created_at": "2026-07-31T07:50:12Z",
|
||||
"updated_at": "2026-07-31T07:50:12Z",
|
||||
"domain": "420.teilzeitladen.xyz/.well-known/assetlinks.json",
|
||||
"self_hosted_domains": [
|
||||
"420.teilzeitladen.xyz/.well-known/assetlinks.json"
|
||||
],
|
||||
"destinations": [
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "420.teilzeitladen.xyz/.well-known/assetlinks.json"
|
||||
}
|
||||
],
|
||||
"app_launcher_visible": false,
|
||||
"allowed_idps": [],
|
||||
"tags": [],
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-07-31T07:50:12Z",
|
||||
"decision": "bypass",
|
||||
"exclude": [],
|
||||
"id": "8f7c4929-376b-4e8f-b0cf-36fb4c686d69",
|
||||
"include": [
|
||||
{
|
||||
"everyone": {}
|
||||
}
|
||||
],
|
||||
"name": "public-bypass",
|
||||
"require": [],
|
||||
"uid": "8f7c4929-376b-4e8f-b0cf-36fb4c686d69",
|
||||
"updated_at": "2026-07-31T07:50:12Z",
|
||||
"reusable": false,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"session_duration": "730h",
|
||||
"enable_binding_cookie": false,
|
||||
"http_only_cookie_attribute": true,
|
||||
"options_preflight_bypass": false,
|
||||
"eager_redirect_cookie_setting": true
|
||||
},
|
||||
{
|
||||
"id": "e6a7991f-466c-4d1d-bac6-4b30fafccce4",
|
||||
"uid": "e6a7991f-466c-4d1d-bac6-4b30fafccce4",
|
||||
"type": "self_hosted",
|
||||
"name": "Terpenfinder v3",
|
||||
"aud": "e4515f7a7740558bf51ff6056e9c52fec25e67d23607209250a92e10cdf574e7",
|
||||
"created_at": "2026-06-22T20:47:31Z",
|
||||
"updated_at": "2026-07-31T07:50:10Z",
|
||||
"domain": "420.teilzeitladen.xyz",
|
||||
"self_hosted_domains": [
|
||||
"420.teilzeitladen.xyz"
|
||||
],
|
||||
"destinations": [
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "420.teilzeitladen.xyz"
|
||||
}
|
||||
],
|
||||
"app_launcher_visible": true,
|
||||
"allowed_idps": [],
|
||||
"tags": [],
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
},
|
||||
{
|
||||
"created_at": "2026-03-06T20:11:40Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "99839886-4ef1-4bad-8cc6-dc864d4dceeb",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "angelikahy@outlook.de"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ip": {
|
||||
"ip": "10.95.10.0/24"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ip": {
|
||||
"ip": "94.154.138.0/24"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "geli",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "99839886-4ef1-4bad-8cc6-dc864d4dceeb",
|
||||
"updated_at": "2026-07-31T07:27:53Z",
|
||||
"reusable": true,
|
||||
"precedence": 2
|
||||
},
|
||||
{
|
||||
"created_at": "2026-07-27T11:37:45Z",
|
||||
"decision": "non_identity",
|
||||
"exclude": [],
|
||||
"id": "bf7d2e5e-3a53-4af1-a64c-a0f0d00703dc",
|
||||
"include": [
|
||||
{
|
||||
"service_token": {
|
||||
"token_id": "1082bad1-6a25-4188-bf6b-220075679e0f"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "terpene-svc",
|
||||
"require": [],
|
||||
"uid": "bf7d2e5e-3a53-4af1-a64c-a0f0d00703dc",
|
||||
"updated_at": "2026-08-05T18:33:01Z",
|
||||
"reusable": true,
|
||||
"precedence": 3
|
||||
}
|
||||
],
|
||||
"session_duration": "730h",
|
||||
"enable_binding_cookie": false,
|
||||
"http_only_cookie_attribute": true,
|
||||
"options_preflight_bypass": false
|
||||
},
|
||||
{
|
||||
"id": "1dbc45ca-1376-4a0d-b608-69db58f1875c",
|
||||
"uid": "1dbc45ca-1376-4a0d-b608-69db58f1875c",
|
||||
"type": "self_hosted",
|
||||
"name": "hass, vw, gitea",
|
||||
"aud": "817b2b82d2b1aa9c12de854c7bce9f608b33721f0827cfded68bdc7c5eb92a46",
|
||||
"created_at": "2026-06-13T08:32:39Z",
|
||||
"updated_at": "2026-07-12T12:43:25Z",
|
||||
"domain": "vw.emsenhuber.net",
|
||||
"self_hosted_domains": [
|
||||
"vw.emsenhuber.net",
|
||||
"hass.emsenhuber.net",
|
||||
"gitea.emsenhuber.net"
|
||||
],
|
||||
"destinations": [
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "vw.emsenhuber.net"
|
||||
},
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "hass.emsenhuber.net"
|
||||
},
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "gitea.emsenhuber.net"
|
||||
}
|
||||
],
|
||||
"app_launcher_visible": true,
|
||||
"allowed_idps": [],
|
||||
"tags": [],
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-06-13T08:34:00Z",
|
||||
"decision": "bypass",
|
||||
"exclude": [],
|
||||
"id": "a8129e37-d3c2-456d-8630-3c6a3449d3f2",
|
||||
"include": [
|
||||
{
|
||||
"everyone": {}
|
||||
}
|
||||
],
|
||||
"name": "bypass",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"uid": "a8129e37-d3c2-456d-8630-3c6a3449d3f2",
|
||||
"updated_at": "2026-06-13T08:48:05Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"session_duration": "24h",
|
||||
"enable_binding_cookie": false,
|
||||
"http_only_cookie_attribute": true,
|
||||
"options_preflight_bypass": false
|
||||
},
|
||||
{
|
||||
"id": "6df5c431-adcf-4dde-805d-4eb22d7c19b4",
|
||||
"uid": "6df5c431-adcf-4dde-805d-4eb22d7c19b4",
|
||||
"type": "app_launcher",
|
||||
"name": "App Launcher",
|
||||
"aud": "015e805251579e50a49668775c2255facb5bc56007ce49f90885f4114584bae2",
|
||||
"created_at": "2026-03-28T16:20:27Z",
|
||||
"updated_at": "2026-07-08T11:56:56Z",
|
||||
"domain": "emsenhuber.cloudflareaccess.com",
|
||||
"allowed_idps": [],
|
||||
"session_duration": "730h",
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"landing_page_design": {},
|
||||
"skip_app_launcher_login_page": false
|
||||
},
|
||||
{
|
||||
"id": "6c32fe23-24d8-433f-b00b-0a3d1558bb30",
|
||||
"uid": "6c32fe23-24d8-433f-b00b-0a3d1558bb30",
|
||||
"type": "warp",
|
||||
"name": "Warp Login App",
|
||||
"aud": "fdfaa967d4118469dc994257f65831caa0162d6c45a14b5205af45e1aeca723b",
|
||||
"created_at": "2026-06-04T18:48:59Z",
|
||||
"updated_at": "2026-06-06T16:53:32Z",
|
||||
"domain": "emsenhuber.cloudflareaccess.com/warp",
|
||||
"allowed_idps": [],
|
||||
"session_duration": "24h",
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
}
|
||||
],
|
||||
"tags": []
|
||||
},
|
||||
{
|
||||
"id": "16aaec78-5951-4cf3-aad5-79f63163b5ea",
|
||||
"uid": "16aaec78-5951-4cf3-aad5-79f63163b5ea",
|
||||
"type": "self_hosted",
|
||||
"name": "*.emsenhuber.net",
|
||||
"aud": "d5bb8c4852895834a0010d6f63882f140cf27faf41f94374532c1f013a15c02d",
|
||||
"created_at": "2026-05-05T11:44:38Z",
|
||||
"updated_at": "2026-05-15T13:30:13Z",
|
||||
"domain": "*.emsenhuber.net",
|
||||
"self_hosted_domains": [
|
||||
"*.emsenhuber.net"
|
||||
],
|
||||
"destinations": [
|
||||
{
|
||||
"type": "public",
|
||||
"uri": "*.emsenhuber.net"
|
||||
}
|
||||
],
|
||||
"app_launcher_visible": true,
|
||||
"allowed_idps": [],
|
||||
"tags": [],
|
||||
"auto_redirect_to_identity": false,
|
||||
"policies": [
|
||||
{
|
||||
"created_at": "2026-02-28T21:26:56Z",
|
||||
"decision": "allow",
|
||||
"exclude": [],
|
||||
"id": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"include": [
|
||||
{
|
||||
"email": {
|
||||
"email": "christoph@emsenhuber.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"login_method": {
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "christoph",
|
||||
"require": [],
|
||||
"connection_rules": {
|
||||
"rdp": {}
|
||||
},
|
||||
"session_duration": "730h",
|
||||
"uid": "8e44f5d1-8257-443e-a797-b3de939952ee",
|
||||
"updated_at": "2026-07-31T07:27:41Z",
|
||||
"reusable": true,
|
||||
"precedence": 1
|
||||
},
|
||||
{
|
||||
"created_at": "2026-05-09T06:45:22Z",
|
||||
"decision": "non_identity",
|
||||
"exclude": [],
|
||||
"id": "5165d139-8733-4d31-a3a5-f6f1d0fd8643",
|
||||
"include": [
|
||||
{
|
||||
"ip": {
|
||||
"ip": "90.146.33.177/32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "bf4",
|
||||
"require": [],
|
||||
"uid": "5165d139-8733-4d31-a3a5-f6f1d0fd8643",
|
||||
"updated_at": "2026-08-07T21:36:42Z",
|
||||
"reusable": true,
|
||||
"precedence": 2
|
||||
},
|
||||
{
|
||||
"created_at": "2026-05-15T13:11:36Z",
|
||||
"decision": "non_identity",
|
||||
"exclude": [],
|
||||
"id": "39fe0e9d-6f63-414d-9d6d-440a7a151f5d",
|
||||
"include": [
|
||||
{
|
||||
"service_token": {
|
||||
"token_id": "65f1821a-f134-4e20-aa66-baf31daddbed"
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "claude-mcp",
|
||||
"require": [],
|
||||
"uid": "39fe0e9d-6f63-414d-9d6d-440a7a151f5d",
|
||||
"updated_at": "2026-07-31T15:44:48Z",
|
||||
"reusable": true,
|
||||
"precedence": 3
|
||||
}
|
||||
],
|
||||
"session_duration": "24h",
|
||||
"enable_binding_cookie": false,
|
||||
"http_only_cookie_attribute": false,
|
||||
"options_preflight_bypass": false,
|
||||
"oauth_configuration": {
|
||||
"enabled": false,
|
||||
"dynamic_client_registration": {
|
||||
"enabled": true,
|
||||
"allowed_uris": [
|
||||
"https://ha-mcp.emsenhuber.net"
|
||||
],
|
||||
"allow_any_on_localhost": true,
|
||||
"allow_any_on_loopback": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": [],
|
||||
"result_info": {
|
||||
"page": 1,
|
||||
"per_page": 1000,
|
||||
"count": 6,
|
||||
"total_count": 6,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
68
docs/cf-backup/tp41-20260901/identity_providers.json
Normal file
68
docs/cf-backup/tp41-20260901/identity_providers.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"id": "72c1291b-a38d-4bc7-af97-5dee04a4f84a",
|
||||
"type": "github",
|
||||
"uid": "72c1291b-a38d-4bc7-af97-5dee04a4f84a",
|
||||
"name": "github",
|
||||
"version": "2c72ea4133061227e63696fb2559488b",
|
||||
"config": {
|
||||
"client_id": "Ov23li2h96hAkGRPJXYV",
|
||||
"redirect_url": "https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback"
|
||||
},
|
||||
"scim_config": {
|
||||
"scim_base_url": "https://emsenhuber.cloudflareaccess.com/scim/72c1291b-a38d-4bc7-af97-5dee04a4f84a",
|
||||
"enabled": false,
|
||||
"user_deprovision": false,
|
||||
"seat_deprovision": false,
|
||||
"group_member_deprovision": false,
|
||||
"identity_update_behavior": "no_action"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "9024c7a6-2d1f-4432-9f48-51593acd1361",
|
||||
"type": "onetimepin",
|
||||
"uid": "9024c7a6-2d1f-4432-9f48-51593acd1361",
|
||||
"name": "",
|
||||
"version": "04b0d281756f552d156faa58ce97f913",
|
||||
"config": {
|
||||
"redirect_url": "https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback"
|
||||
},
|
||||
"scim_config": {
|
||||
"enabled": false,
|
||||
"user_deprovision": false,
|
||||
"seat_deprovision": false,
|
||||
"group_member_deprovision": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "c7571880-2c63-4b66-a52a-0051802f7444",
|
||||
"type": "google",
|
||||
"uid": "c7571880-2c63-4b66-a52a-0051802f7444",
|
||||
"name": "google",
|
||||
"version": "6c1595b3026ae3196c70977c3924befb",
|
||||
"config": {
|
||||
"client_id": "276709275903-b3q55lsj203v4strbhh5mub76cib867e.apps.googleusercontent.com",
|
||||
"redirect_url": "https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback"
|
||||
},
|
||||
"scim_config": {
|
||||
"scim_base_url": "https://emsenhuber.cloudflareaccess.com/scim/c7571880-2c63-4b66-a52a-0051802f7444",
|
||||
"enabled": false,
|
||||
"user_deprovision": false,
|
||||
"seat_deprovision": false,
|
||||
"group_member_deprovision": false,
|
||||
"identity_update_behavior": "no_action"
|
||||
}
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": [],
|
||||
"result_info": {
|
||||
"page": 1,
|
||||
"per_page": 200,
|
||||
"count": 3,
|
||||
"total_count": 3,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
29
docs/cf-backup/tp41-20260901/organizations.json
Normal file
29
docs/cf-backup/tp41-20260901/organizations.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"result": {
|
||||
"auth_domain": "emsenhuber.cloudflareaccess.com",
|
||||
"created_at": "2024-02-22T13:41:46Z",
|
||||
"login_design": {
|
||||
"background_color": "#eeeeee"
|
||||
},
|
||||
"name": "bf4.cloudflareaccess.com",
|
||||
"updated_at": "2026-07-09T17:34:55Z",
|
||||
"is_ui_read_only": false,
|
||||
"has_migrated_private_apps": true,
|
||||
"allow_authenticate_via_warp": false,
|
||||
"warp_auth_non_browser_401": false,
|
||||
"cache_device_posture": true,
|
||||
"deny_unmatched_requests": false,
|
||||
"deny_unmatched_requests_exempted_zone_names": [],
|
||||
"mfa_config": {
|
||||
"allowed_authenticators": [
|
||||
"biometrics",
|
||||
"security_key",
|
||||
"totp"
|
||||
],
|
||||
"session_duration": "24h"
|
||||
}
|
||||
},
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": []
|
||||
}
|
||||
51
docs/cf-backup/tp41-20260901/service_tokens.json
Normal file
51
docs/cf-backup/tp41-20260901/service_tokens.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"result": [
|
||||
{
|
||||
"client_id": "ad1b47dee8ba9625eebb30247d163dda.access",
|
||||
"created_at": "2026-05-15T13:09:45Z",
|
||||
"expires_at": "2027-05-15T13:19:03Z",
|
||||
"id": "65f1821a-f134-4e20-aa66-baf31daddbed",
|
||||
"name": "claude-mcp",
|
||||
"updated_at": "2026-07-31T14:32:11Z",
|
||||
"duration": "8760h",
|
||||
"client_secret_version": 4,
|
||||
"previous_client_secret_expires_at": "2026-07-31T14:32:11Z",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"client_id": "e8a56791f7f534f3eaff8629d8fe902c.access",
|
||||
"created_at": "2026-07-27T11:36:26Z",
|
||||
"expires_at": "2027-08-05T18:32:14Z",
|
||||
"id": "a6be7efa-8367-446d-99b8-67f25f173371",
|
||||
"name": "terpene-verify",
|
||||
"updated_at": "2026-08-05T18:32:14Z",
|
||||
"duration": "8760h",
|
||||
"last_seen_at": "2026-08-02T20:49:21Z",
|
||||
"client_secret_version": 3,
|
||||
"previous_client_secret_expires_at": "2026-07-31T10:00:00Z",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"client_id": "0ec06d3a6dc6d689c13407591b286e5b.access",
|
||||
"created_at": "2026-08-05T18:32:36Z",
|
||||
"expires_at": "2027-08-05T18:32:36Z",
|
||||
"id": "1082bad1-6a25-4188-bf6b-220075679e0f",
|
||||
"name": "terpene-verify-v2",
|
||||
"updated_at": "2026-08-05T18:32:36Z",
|
||||
"duration": "8760h",
|
||||
"last_seen_at": "2026-08-27T12:47:30Z",
|
||||
"client_secret_version": 1,
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"errors": [],
|
||||
"messages": [],
|
||||
"result_info": {
|
||||
"page": 1,
|
||||
"per_page": 1000,
|
||||
"count": 3,
|
||||
"total_count": 3,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,40 @@
|
||||
# Cloudflare-Tunnel — Mapping & #1033-Diagnose (Single Source of Truth)
|
||||
|
||||
> **Aktueller Stand: → §10 (2026-07-10, TP16 UMGESETZT ✅).** §9 = Analyse/Zielbild, §10 = As-Built.
|
||||
> Abschnitte 1–8 sind Historie (Track A, 2026-06-30); die „3 Connectors gut/Zielbild"-Aussagen dort sind
|
||||
> durch §9/§10 **überholt** (Round-Robin = macvlan-Host-Isolation → 1/N-Ausfälle). Track A aus `docs/handoff-cf-tunnel-1033.md`.
|
||||
> 🆕 **SSoT-Wechsel im Aufbau (TP44, seit 2026-09-02):** Die CF-Estate (Tunnel, WARP-Connector,
|
||||
> VPC-Services, Hyperdrive, Workers, Access-Apps) wird als **native `nautobot.cloud`-Objekte** in
|
||||
> Nautobot (`10.40.20.30`) geführt — Etappe 1 (manuelle Erstbefüllung) ✅. Seeder:
|
||||
> `nautobot/tp44-cf-estate-seed.py`, Detail: `docs/handoff-20260902-cf-estate-nautobot-ssot.md`.
|
||||
> **CF bleibt operativer Master, Nautobot = Dokumentations-SSoT.** Dieses File bleibt gültige Historie
|
||||
> und As-Built-Log; die *strukturierte* Estate liest man ab jetzt in Nautobot. Etappe 2 (CF-API→Nautobot-Sync)
|
||||
> ist offen.
|
||||
|
||||
> **Aktueller Stand: → §0 (unten).** §1–16 sind Historie/As-Built-Log früherer Sessions und beschreiben
|
||||
> Topologien, die **nicht mehr live** sind (v.a. das 3-Tunnel-HA `bf-mm`/`bf-nas`/`bf-pve`). §9 = Analyse,
|
||||
> §10–15 = As-Built des inzwischen abgelösten 3-Tunnel-Designs. Track A aus `docs/handoff-cf-tunnel-1033.md`.
|
||||
|
||||
## §0 — Live-Ist-Stand (2026-09-08, maßgeblich)
|
||||
|
||||
> Der einzige aktuelle Topologie-Stand. **§1–16 nicht als aktuelle Konfiguration lesen** — insbesondere das
|
||||
> 3-Tunnel-HA `bf-mm`/`bf-nas`/`bf-pve` (§10–15) existiert seit dem TP16.3-Cutover (bf-public/Caddy,
|
||||
> 2026-08-27) **nicht mehr**. Strukturierte Estate = Nautobot (TP44, deckt sich mit diesem Stand);
|
||||
> operativer Master = Cloudflare. Read-only gemessen gegen die CF-API (`cfd_tunnel`, `warp_connector`,
|
||||
> `teamnet/routes`) am 2026-09-08.
|
||||
|
||||
**cloudflared-Tunnel (live) — es gibt genau drei:**
|
||||
|
||||
| Tunnel | ID | Conns | Zweck |
|
||||
|---|---|---|---|
|
||||
| **bf-public** | `48d3b0b6-7233-4781-a76a-1de4a5e957ce` | 2, healthy | **einziger öffentlicher BF-Tunnel** (TP31/TP16.3), erstellt 2026-08-27 |
|
||||
| **fm.emsenhuber.net** | `b697d124-53bf-4a33-8fcf-384cced4db1a` | 1, healthy | Standort FM (`ds-fm`, `gateway-fm`), separat |
|
||||
| **terpene-db** | `f2d2fc8a-54ae-41df-b09a-97312cdb9fe2` | 1, healthy | DB-Pfad (Hyperdrive→VPC-Service), Rebuild 2026-09-01 — s. §17 |
|
||||
|
||||
**bf-public-Ingress** → alle vier auf **Caddy `10.40.20.40:443`** (Caddy macht das Fan-out), catch-all 404:
|
||||
`vw` · `hass` · `n8n` · `gitea` (`.emsenhuber.net`).
|
||||
|
||||
**WARP / Private Access — nativer Mesh, KEIN cloudflared:**
|
||||
- warp_connector **bf-core-mesh** `d1da7c8a-2736-4cbb-8af1-32db5393fb9c`, healthy — nativer
|
||||
WireGuard-Mesh-Node auf dem Core (TP16.1). **Live und produktiv** (nicht mehr „gated/Konzept" wie in §14).
|
||||
- Routen: `10.40.0.0/16` → **bf-core-mesh** · `10.101.0.0/24` → **fm**. Ein vnet `vnetemsenhuber` (default).
|
||||
|
||||
## 1. Alle Tunnel im Account (`393c…66c36`)
|
||||
| Tunnel | ID | Status | Conns | Verwendung |
|
||||
@@ -226,6 +258,9 @@ Der macmini ist vollwertiger dritter Knoten (nicht „vergessen").
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>🗄️ <b>ARCHIV (§10–16)</b> — überholtes 3-Tunnel-HA <code>bf-mm</code>/<code>bf-nas</code>/<code>bf-pve</code>. Seit dem TP16.3-Cutover (2026-08-27) nicht mehr live — siehe §0. Aufklappen nur für die Historie.</summary>
|
||||
|
||||
## 10. AS-BUILT 2026-07-10 (TP16 umgesetzt) — reziprokes 3-Tunnel-HA ✅
|
||||
> Gebaut & verifiziert in eigener Session. Round-Robin-#1033 **strukturell weg** (Loop-Gegentest 0×530 über alle 19 Live-FQDNs, HA per Host-Ausfall-Sim bewiesen). Schritte 1–4+HA durch; **Schritt 5 (Access/WARP + `vw`) offen** (user-gated).
|
||||
|
||||
@@ -329,6 +364,10 @@ Letzte in §9.2/§8 als „bleibt `.41`" geführte Origin-Klasse (`pve .41.100`,
|
||||
|
||||
## 14. Richtungsentscheid 2026-07-16 — Private Access via native Cloudflare Mesh (WARP Connector) auf dem CRS326 Core-Switch (TP16.1)
|
||||
|
||||
> ✅ **Nachtrag 2026-09-08 (live):** umgesetzt. warp_connector **bf-core-mesh** (`d1da7c8a-…`) ist healthy
|
||||
> und trägt die Route `10.40.0.0/16` — der „Scharfschalten = eigene Session, gated"-Status unten ist
|
||||
> überholt. Siehe §0.
|
||||
|
||||
> ✅ **Update 2026-07-22 (User-Entscheid):** Ziel-Device retargeted von **ap1** auf den **CRS326 Core-Switch** — konsistent mit TP15-Endstand (kein RB5009, Router bleibt ap1/ap2) und TP21s Kabel-Fabric-Modell. Reine Ziel-Doku-Änderung, Scharfschalten bleibt gated bis TP21 den CRS326 abdeckt. Der Rest dieser Sektion ist entsprechend auf den neuen Zielhost umgeschrieben; CRS326 ist aktuell noch Werkszustand, Management-IP/Interface TBD.
|
||||
|
||||
**Trennung der Concerns (wichtig):**
|
||||
@@ -443,3 +482,42 @@ SSoT und hat eine ganze Architektur getragen.
|
||||
Netzwerk-Namespace, sieht ohnehin alles), und die cloudflared-Connectoren laufen auf **ap1/ap2** —
|
||||
eigene Maschinen, auf denen die Blindheit prinzipiell nicht auftreten kann. Der Shim bleibt als Option
|
||||
für den Fall, dass später doch ein Dienst neben macvlan-Nachbarn einziehen soll.
|
||||
|
||||
</details>
|
||||
|
||||
## 17. Terpenfinder-DB-Pfad neu aufgebaut 2026-09-02 (Fremdprojekt-Handout blaueblüten)
|
||||
|
||||
**Auslöser:** Handout `blaueblueten-n8n/docs/handout-bf-infra-db-pfad-20260902.md` — der Cloudflare-Worker
|
||||
`terpene` (`420.teilzeitladen.xyz`) lieferte `503 CONNECTION_CLOSED …hyperdrive.local:5432` auf allen
|
||||
`/api/*`-Reads.
|
||||
|
||||
**Root-Cause:** TP16.3 §6 hat beim Alttunnel-Abbau den Container **`terpene-cloudflared` (LXC 400)** mit
|
||||
abgeräumt, obwohl das Runbook ihn ausdrücklich als „nicht anfassen" markierte. Damit war der Tunnel
|
||||
`terpene-db` (`b83b68f0`) `deleted_at 2026-08-31`. Der **VPC-Service** `terpene-db` (`019fa3d5`) zeigte
|
||||
weiter auf diese tote ID. Der Public-Weg (PWA→`bf-public`/Caddy) und der **DB-Weg**
|
||||
(Hyperdrive→VPC-Service→cloudflared→Postgres) wurden verwechselt — der DB-Weg ist unabhängig und blieb
|
||||
ungesichert.
|
||||
|
||||
**Verworfene Optionen (live geprüft):**
|
||||
- **Mesh (`bf-core-mesh`, warp_connector):** CF lehnt ab — `5101: Tunnel is not a cloudflared tunnel`.
|
||||
Ein VPC-Service akzeptiert im `host.network.tunnel_id` **nur einen cloudflared-Tunnel**, keinen
|
||||
warp_connector. (Mesh geht nur über *VPC Networks*, die Hyperdrive nicht nutzt.)
|
||||
- **`bf-public` (AP-Endpoints) wiederverwenden:** bräuchte eine neue Firewallregel `vlan99→10.40.20.20:5432`
|
||||
(Loch mgmt→INFRA, heute nur `.20.40:443` offen, Regel `*42`) **plus** `warp-routing` auf dem geteilten
|
||||
Public-Tunnel (steht auf `false`) — Projekt-Vermischung. Verworfen.
|
||||
|
||||
**Umgesetzt (Option B):** eigener neuer cloudflared-Tunnel neben der DB.
|
||||
|
||||
| Objekt | Wert |
|
||||
|---|---|
|
||||
| cfd_tunnel `terpene-db` (neu) | **`f2d2fc8a-54ae-41df-b09a-97312cdb9fe2`**, remotely-managed, healthy/4 Conns |
|
||||
| Connector | Container `terpene-cloudflared` auf **LXC 400** (VLAN20, `.20.126`), `restart=unless-stopped`, Token per `--env-file` |
|
||||
| VPC-Service `terpene-db` | `019fa3d5-…` `host.network.tunnel_id` → `f2d2fc8a` (PUT 200, 2026-09-01T23:57Z) |
|
||||
| Firewall | **0 Änderungen** — Connector und DB im selben VLAN20, kein Cross-VLAN |
|
||||
| Tombstone | Alttunnel `b83b68f0` bleibt soft-deleted, kein Aufräumbedarf |
|
||||
|
||||
🔑 **Gotcha 1:** VPC-Service = `/accounts/{id}/connectivity/directory/services/{id}`, Update ist **PUT**
|
||||
(voller Body), **nicht** unter `/vpc/…`. 🔑 **Gotcha 2:** der Repo-`CF_API_TOKEN` (`mcp/cloudflare/.env`)
|
||||
darf `cfd_tunnel` (Create lief per curl), aber **nicht** die Workers-VPC-Resource — dort `10000 Auth error`;
|
||||
der PUT lief über den `cloudflare`-MCP-Credential. 🔑 **Merkregel:** vor einem AP-basierten Weg immer die
|
||||
Egress-VLAN-Seite der Connectoren prüfen — `bf-public` sitzt auf **vlan99**, nicht vlan20.
|
||||
|
||||
186
docs/handoff-20260901-fund-e-hebel1-zurueckgebaut.md
Normal file
186
docs/handoff-20260901-fund-e-hebel1-zurueckgebaut.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# Handoff 2026-09-01 — Hebel 1 widerlegt und zurückgebaut, 7.24.1 ist der Verdächtige
|
||||
|
||||
> Vorgänger: [`handoff-20260831-tp27-upgrade-und-hebel1-befund.md`](handoff-20260831-tp27-upgrade-und-hebel1-befund.md).
|
||||
> **Dieses Dokument ist der Stand danach.** Offene Aufgabe: **eine Messung am 2026-09-02 früh.**
|
||||
|
||||
## Die Messung, die Hebel 1 widerlegt
|
||||
|
||||
| Fenster | Bedingung | iPhone-`reauthenticating` | pro Stunde |
|
||||
|---|---|---|---|
|
||||
| 31.08. 07:00–08:00 | Baseline | **79** | 79 |
|
||||
| 31.08. 08:09–14:36 | **nur Hebel 1** (ROS 7.24) | **124** | ~19 |
|
||||
| 31.08. 14:37–24:00 | Hebel 1 + **7.24.1** | 17 | ~1,8 |
|
||||
| 01.09. 00:00–07:57 | Hebel 1 + 7.24.1 | **0** | 0 |
|
||||
|
||||
6,4 Stunden Hebel 1 **allein** haben nichts verbessert. Der Einbruch fällt exakt auf den
|
||||
Core-Reboot um 14:36 — also auf das TP27-Upgrade, nicht auf den Hebel.
|
||||
|
||||
**Beide Gegenproben bestanden** — ohne sie wäre die Null wertlos:
|
||||
- **War das Telefon da?** Ja: 27 Zeilen am 01.09., mehrfaches Roaming, live verbunden.
|
||||
- **Lief das Logging?** Ja: keine Lücke > 15 min in der Tagesdatei.
|
||||
|
||||
## 🔴 Widerspruch zu einer Parallelsession — und wie er aufzulösen ist
|
||||
|
||||
Eine zweite Session hat in der Nacht denselben Fall bearbeitet und kam zum **gegenteiligen**
|
||||
Schluss: [`handoff-20260901-tp25-ap2-verdacht.md`](handoff-20260901-tp25-ap2-verdacht.md) wertet
|
||||
Fund E als **geheilt durch Hebel 1** und empfiehlt, ihn zu **committen**.
|
||||
|
||||
**Ihr Beleg war eine Fehlmessung.** Zitiert wird
|
||||
`get_log topics=[wireless] prefix=reauthenticating sinceMinutes=1440` → `total 0`. Das ist der
|
||||
**flüchtige Ringpuffer des Routers**, nicht der Kollektor:
|
||||
|
||||
```
|
||||
/log am Core, live geprüft 2026-09-01 09:1x:
|
||||
1000 Zeilen im Ringpuffer, ältester Eintrag 2026-09-01 00:38:58 ← keine 9 Stunden Tiefe
|
||||
```
|
||||
|
||||
Der Core wurde am 31.08. um **14:36** neu gestartet; der Puffer war danach leer und um 01:18
|
||||
längst überschrieben. Eine 1440-Minuten-Abfrage konnte den 31.08. Vormittag **nicht sehen** —
|
||||
`total 0` heißt „im Puffer nichts", nicht „in 24 h nichts". Genau diese Falle war der Anlass, am
|
||||
30.08. das persistente Logging einzurichten (CLAUDE.md: „ein seit Wochen gemeldetes Client-Problem
|
||||
war rückwirkend nicht diagnostizierbar").
|
||||
|
||||
**Der zweite Einwand — die 124 seien Reboot-Artefakte — trägt ebenfalls nicht.** Die Upgrade-Reboots
|
||||
waren ap2 08:56, core 14:36, ap1 14:50, branch 14:52. Zwischen **09:00 und 14:36 gab es keinen
|
||||
Reboot**, und in diesem Fenster stehen im Kollektor 09h=1, 11h=2, 12h=20, 13h=31, 14h=70 — **alle
|
||||
vom iPhone allein**, also nach dem eigenen Gotcha der Session (viele MACs = Infrastruktur, eine MAC
|
||||
= Client) ein Client-Befund. Dazu Christophs **zwei erlebte Ausfälle** um 13:16 und 14:23.
|
||||
|
||||
⚖️ **Auflösung: der Rückbau IST das Experiment, das den Streit entscheidet.** Steht `ft-over-ds`
|
||||
wieder auf `yes` und bleibt es trotzdem ruhig, war 7.24.1 die Ursache. Kommt das Hämmern zurück,
|
||||
hatte die Parallelsession recht und Hebel 1 wird als neue Transaktion erneut gezogen. **Vor dem
|
||||
2026-09-02 früh sollte niemand committen.**
|
||||
|
||||
✅ **Unabhängig davon wertvoll: ihr `ap2`-Befund.** Am 31.08. um 23:02 meldete Christoph eine
|
||||
Störung am Schreibtisch; die Session maß **−80 dBm bei 2 m Abstand** zu ap2, `not responding` bei
|
||||
−82, und **0 Clients auf ap2** bei 29 auf ap3. Das ist weder Coverage noch FT, sondern ein
|
||||
Hardware-/Störungsverdacht (Kandidat: DTU auf ch11, Transaktion `TP17.1-dtu-pin-ap2`). **Das
|
||||
erklärt den 23:02-Schmerz, den mein Rückbau nicht adressiert** — eigener Strang, braucht eine
|
||||
In-situ-Messung.
|
||||
|
||||
## Was heute getan wurde: Rückbau statt Commit
|
||||
|
||||
**Warum nicht committen:** Solange Hebel 1 steht, sind zwei Änderungen gleichzeitig aktiv. Der
|
||||
Rückbau isoliert das Upgrade — **er ist der Test**, nicht bloß Aufräumen. Und weil das GC-Template
|
||||
in Z. 220 ohnehin `ft-over-ds=yes` führt, kommt die Compliance **ohne Template-Änderung** zurück.
|
||||
|
||||
Weg **symmetrisch zum Hinweg** (Christoph-Entscheid), also am Gerät, nicht über GC:
|
||||
|
||||
```
|
||||
/system backup save name=pre-tp25-funde-rollback # 0
|
||||
/interface wifi security set [find name="sec-main"] ft-over-ds=yes
|
||||
/interface wifi capsman remote-cap provision [find]
|
||||
```
|
||||
|
||||
Der Rückbau-Vorschlag aus dem Snapshot zeigte **genau eine** Abweichung — kein Kollateral-Drift:
|
||||
```
|
||||
JETZT NUR AM GERAET ... ft=yes ft-over-ds=no name=sec-main
|
||||
IM SNAPSHOT, FEHLT ... ft=yes ft-over-ds=yes name=sec-main
|
||||
```
|
||||
|
||||
### Abnahme
|
||||
|
||||
| Prüfung | Ergebnis |
|
||||
|---|---|
|
||||
| `ft-over-ds` am Core | **`ft=yes ft-over-ds=yes`** ✓ |
|
||||
| CAPs | 3 × `Ok`, CAPWAP-Verbindung **ununterbrochen** (17 h) — `provision` trennt sie nicht |
|
||||
| VAPs **am CAP** gelesen | ap2 **9/9** `running`, ap3 **9/9** `running` |
|
||||
| **Frische DHCP-Lease** (die vorgeschriebene Abnahme) | iPhone `10.40.10.196`, `bound`, `expires-after 23h58m56s` bei 24 h Laufzeit ⇒ **~1 min alt** |
|
||||
| Clients | 25 → 28 zurück |
|
||||
| Transaktion | `gc-transaktion.py status` → **`zurueckgebaut`**, kein Drift im Scope |
|
||||
| Compliance | **140/140, 0 Drifts** — ohne jede Template-Änderung, wie vorhergesagt |
|
||||
|
||||
### ⚠️ Zwei Nebenbefunde beim Compliance-Lauf
|
||||
|
||||
**1. `gc-configplan.py --refresh-compliance` scheitert STILL, wenn `NAUTOBOT_TOKEN` fehlt** —
|
||||
Ausgabe „NAUTOBOT_TOKEN nicht gesetzt", danach **Exit-Code 0**. Wer nur den Rückgabewert prüft,
|
||||
hält einen nie gelaufenen Compliance-Check für erfolgreich. Behelf in dieser Session:
|
||||
```bash
|
||||
NAUTOBOT_TOKEN="$(sed -n 's/^[[:space:]]*-[[:space:]]*NAUTOBOT_SUPERUSER_API_TOKEN=//p' \
|
||||
docs/nas-vlan20/stacks/210-nautobot.yml | head -1)" python3 nautobot/gc-configplan.py --refresh-compliance
|
||||
```
|
||||
Dauerhafte Antwort wäre `NAUTOBOT_TOKEN` in `~/.secrets/exports.zsh` (steht schon im Handoff vom
|
||||
31.08. als offener Punkt). ⇒ **Der Exit-Code gehört gefixt**, sonst wiederholt sich das.
|
||||
|
||||
**2. Die Compliance-Zahl ist von 135 auf 140 gestiegen — das ist erklärt, nicht übergangen.**
|
||||
Es gibt jetzt **28 ComplianceRules** statt 27 (5 Geräte × 28 = 140). Neu ist **`interface-veth`**,
|
||||
angelegt **2026-08-31 20:04**, also **nach** der Session vom 31.08. und **nicht** in dieser hier.
|
||||
🔴 **Wer sie angelegt hat, ist offen** — `veth` betrifft Container auf RouterOS. Bitte klären,
|
||||
bevor jemand die Zahl als Basislinie zitiert.
|
||||
|
||||
## 🔴 Die `cap-wifiN`-Karte ist beim Provisionieren SOFORT wieder gewandert
|
||||
|
||||
Innerhalb dieser Session, zwischen zwei Reads im Abstand von Minuten:
|
||||
|
||||
| | vor dem Rückbau (galt 31.08. 14:52 – 01.09. 08:2x) | **ab jetzt** |
|
||||
|---|---|---|
|
||||
| ap3 | `cap-wifi3` / `cap-wifi4` | `cap-wifi3` / **`cap-wifi5`** |
|
||||
| ap2 | `cap-wifi5` / `cap-wifi6` | **`cap-wifi4`** / `cap-wifi6` |
|
||||
| ap1 | `cap-wifi1` / `cap-wifi2` | **getauscht** (`cap-wifi2` / `cap-wifi1`) |
|
||||
|
||||
Belastbar ist nur die **`radio-mac`**, weil sie am Gerät hängt:
|
||||
`ap3 …:9F` = 5 GHz → `cap-wifi3` · `ap3 …:A0` = 2,4 GHz → `cap-wifi5` ·
|
||||
`ap2 …:3E` → `cap-wifi4` · `ap2 …:3F` → `cap-wifi6` · `ap1 …:E5` → `cap-wifi2` · `…:E6` → `cap-wifi1`
|
||||
*(Bandzuordnung für ap2/ap1 in dieser Session **nicht** nachgemessen — nicht raten.)*
|
||||
|
||||
⚠️ **Folge für die Auswertung:** Logzeilen vom 01.09. **vor** ca. 08:25 gehören zur linken Spalte.
|
||||
Sie sind zuschreibbar, weil im ganzen Messfenster **0 `caps`-Ereignisse** standen — das war
|
||||
Glück, kein Verdienst.
|
||||
|
||||
## Die Messung am 2026-09-02
|
||||
|
||||
```bash
|
||||
ssh root@10.40.20.100 "pct exec 400 -- sh -c '
|
||||
D=/opt/tp5-syslog/log/10.40.20.1;
|
||||
echo -n \"caps: \"; grep -c \" caps,\" $D/2026-09-02.log;
|
||||
echo -n \"reauth: \"; grep reauthenticating $D/2026-09-02.log | grep -c E1:AF:09;
|
||||
echo -n \"iPhone da? \"; grep -c E1:AF:09 $D/2026-09-02.log'"
|
||||
```
|
||||
**Reihenfolge einhalten:** erst `caps` (Rejoins erzeugen Bursts, die wie ein Client-Problem
|
||||
aussehen), dann `reauth`, dann die Anwesenheitsprobe. Vergleichszeitraum ist **07:00–08:00** —
|
||||
dort standen am 31.08. 79 Ereignisse, am 01.09. null.
|
||||
|
||||
| Ergebnis | Schluss | Nächster Schritt |
|
||||
|---|---|---|
|
||||
| weiter ~0 | **7.24.1 hat es behoben**, Hebel 1 war wirkungslos | Fund E schließen; offen bleibt das Band-Ping-Pong (s. u.) |
|
||||
| Hämmern kommt zurück | Hebel 1 hat doch beigetragen | neue Transaktion, `ft-over-ds=no` erneut — diesmal auf 7.24.1 **isoliert** |
|
||||
|
||||
## Neues Symptom, das die Reauth-Schleife ablöst: Band-Ping-Pong
|
||||
|
||||
Am 01.09. hämmert nichts mehr, aber das iPhone oszilliert zwischen den **beiden Bändern desselben
|
||||
AP** (alte Karte, also ap3 5 GHz ↔ ap3 2,4 GHz):
|
||||
```
|
||||
01:49:14 ap3-2,4G → ap3-5G (−65)
|
||||
01:49:32 ap3-5G → ap3-2,4G (−55) ← 18 s später zurück
|
||||
01:50:28 ap3-2,4G → ap3-5G (−69)
|
||||
07:45 / 07:46 / 07:47 dasselbe im Minutentakt
|
||||
```
|
||||
Verbindungsalter beim Nachsehen: **1:26 min** bei −72 dBm. Das ist kein Auth-Problem mehr, sondern
|
||||
genau das, wofür **Hebel 3 (`2g-probe-delay=yes`)** gedacht war. **Nicht** in diesem Durchgang.
|
||||
|
||||
## ⚠️ Zwei Anomalien aus dem Gesamtlog — eigener Durchgang, nicht nebenbei
|
||||
|
||||
**1. Das Log besteht zu 98,4 % aus Rauschen.** 5457 von 5548 Zeilen sind Firewall-Drops, davon
|
||||
**3810 MNDP-Broadcasts (udp/5678) der eigenen Netzgeräte** (ap1/ap2/ap3/branch, je ~950/Tag).
|
||||
Nutzsignal 1,6 % — in genau dem Log, das unser Diagnosewerkzeug ist.
|
||||
|
||||
**2. 🔴 IGMP aus VLAN30 wird verworfen** (funktional, nicht kosmetisch):
|
||||
```
|
||||
in:vlan30 proto 2, 10.40.30.211->224.0.0.251
|
||||
in:vlan30 proto 2, 10.40.30.215->224.0.0.251
|
||||
```
|
||||
Membership-Reports für die **mDNS-Gruppe** von zwei IoT-Geräten. Der Core betreibt
|
||||
`mdns-repeat-ifaces` — er verwirft also Anmeldungen für genau den Dienst, den er weiterreichen
|
||||
soll. Kandidat für Matter/HomeKit-Discovery-Probleme (TP12.1).
|
||||
|
||||
**3. Nebenbefund zur Hypothese:** `dirtyvader-iot` (mit `ft=no`) hatte am 31.08. **7
|
||||
`reauthenticating`**, und `association rejected, no cached PMK` tritt dort ebenfalls auf. Die
|
||||
ursprüngliche Trennschärfe „93/93 nur auf der `ft=yes`-SSID" galt für die Nacht-Baseline, **nicht
|
||||
für den vollen Tag**. `no cached PMK` ist PMKSA-Caching und nicht FT-spezifisch.
|
||||
|
||||
## Unverändert offen
|
||||
|
||||
1. TP25-Messrunde mit Rundgang (`bash docs/tp25-runde.sh`) — **Terrasse und Arbeitszimmer**;
|
||||
`ap-map` dabei neu einfrieren (s. o., sie wandert bei jedem Provision).
|
||||
2. Passwort-Rotation TP30 (Admin-PW am 08-30 verbrannt).
|
||||
3. ap1-Umzug ans Sideboard (`core ether3`, `5260/Ce`, Frequenz-**Liste**, `tx-power` vorher messen).
|
||||
69
docs/handoff-20260901-n8n-mcp-ssrf.md
Normal file
69
docs/handoff-20260901-n8n-mcp-ssrf.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Handoff 2026-09-01 — n8n-mcp SSRF-Block ✅ GEFIXT + in Portainer-Stack 174 gefaltet
|
||||
|
||||
## Kontext
|
||||
Aus TP10 (Terpenfinder Auto-Refresh, Repo `blaueblueten-n8n`) ausgelagerter bf-infra-Task:
|
||||
der n8n-MCP war einsatzfähig, aber seine Anbindung an die **n8n-API** war blockiert. Diese
|
||||
Session hat den Blocker behoben und die Container-Definition sauber verortet.
|
||||
|
||||
## Befund (Ausgangslage)
|
||||
- **Netz war nie das Problem:** aus dem `n8n-mcp`-Container erreichten **beide** Wege n8n —
|
||||
intern `http://n8n:5678` → HTTP 200, öffentlich `https://n8n.emsenhuber.net/healthz` → HTTP 200.
|
||||
- **Einziger Blocker = App-eigener SSRF-Guard** von n8n-mcp (v2.57.1 → nach Redeploy 2.77.0):
|
||||
`N8N_API_URL=http://n8n:5678` löst auf die private Docker-Bridge-IP `172.19.0.3` auf, und der
|
||||
Guard lehnte private IPs im Default-Modus `strict` ab (`SSRF protection: Private IP addresses
|
||||
not allowed`, `connected:false`). Der API-Client validiert `N8N_API_URL` über genau diesen
|
||||
Guard (`/app/dist/services/n8n-api-client.js:104` → `SSRFProtection.validateWebhookUrl`).
|
||||
- **SSoT-Drift (mit-gefixt):** der laufende Container war ein **Waise** aus
|
||||
`~/dev/homelab-cline/n8n-mcp-deploy/docker-compose.yml` (kein Git-Repo), und dieses File stimmte
|
||||
mit dem laufenden Container nicht überein (File: `https://n8n.emsenhuber.net` + Netz `web`;
|
||||
Container: `http://n8n:5678` + Netz `n8n_default`). `n8n`+`n8n-redis` liefen dagegen im
|
||||
Portainer-Stack **174** (`n8n`, Endpoint 20 = macmini).
|
||||
|
||||
## Fix (durchgeführt 2026-09-01)
|
||||
Entscheidung (User): **intern + permissive**, und **n8n-mcp in Portainer-Stack 174 falten**.
|
||||
|
||||
1. **SSRF entschärft:** `WEBHOOK_SECURITY_MODE=permissive` gesetzt → private/LAN-IP für
|
||||
`N8N_API_URL=http://n8n:5678` erlaubt. Bleibt auf der Docker-Bridge, **kein** CF/Tunnel/Caddy-
|
||||
Umweg, keine 10-s-DNS-Falle, unabhängig von der Edge. Vertretbar, weil dieser Container
|
||||
ausschließlich mit dem trusted LAN-n8n redet.
|
||||
2. **Waise beseitigt:** orphan-Container entfernt (`docker rm -f n8n-mcp`), n8n-mcp als **dritter
|
||||
Service** in Stack 174 aufgenommen (neben `n8n`+`redis`, gemeinsames Default-Netz `n8n_default`,
|
||||
`depends_on: n8n`). Stack via Portainer-API redeployt (`PUT /api/stacks/174?endpointId=20`,
|
||||
`prune:false`).
|
||||
3. **Erhalten geblieben:** Bearer (`AUTH_TOKEN`==`MCP_AUTH_TOKEN`, len 64) **unverändert** →
|
||||
bestehende Clients (opencode `http://10.40.20.167:3001/mcp`) laufen weiter; Host-Port-Bind
|
||||
`10.40.20.167:3001:3000` → Caddy-Route `n8n-mcp.emsenhuber.net` (Caddyfile Z. 75) intakt;
|
||||
Daten-Volume als **`external`** wiederverwendet (`n8n-mcp-deploy_n8n-mcp-data`, `nodes.db`
|
||||
bleibt) — eigener `N8N_API_KEY` von n8n-mcp (≠ n8n) unverändert.
|
||||
|
||||
## Verifikation (nicht behauptet — gemessen)
|
||||
- `SSRFProtection.validateWebhookUrl("http://n8n:5678")` im Container → `valid:true`,
|
||||
`resolved:172.19.0.3`, `mode:permissive`.
|
||||
- MCP-Tool `n8n_health_check` (voller Handshake) → `{"success":true,"status":"ok",
|
||||
"apiUrl":"http://n8n:5678","mcpVersion":"2.77.0","upToDate":true}`.
|
||||
- `n8n`+`n8n-redis` behielten Container-ID **und** `StartedAt` (2026-07-29) → **kein n8n-Downtime**
|
||||
beim Redeploy (nur der neue Service wurde erstellt).
|
||||
|
||||
## SSoT / Ablage
|
||||
- **Master der Stack-Definition = Portainer-Stack 174** (`n8n`, Endpoint 20, macmini).
|
||||
- Gitignored Repo-Mirror + Rollback: `docs/macmini-vlan20/stacks/174-n8n.yml` (neuer Stand) und
|
||||
`…/174-n8n.orig-pre-mcp-fold-20260901.yml` (Vorzustand). Neu gitignored: `docs/macmini-vlan20/stacks`.
|
||||
- INVENTORY-Eintrag `mcp/INVENTORY.md` (n8n-mcp) aktualisiert.
|
||||
|
||||
## Offene Punkte
|
||||
- 🔴 **TP30 Posten #8:** beim Ausgeben des Stack-174-Files ist `N8N_SMTP_PASS` (Gmail-App-PW
|
||||
`johnny.claw.0x00@gmail.com`) ins Transkript geraten (Redaktionsmuster hatte `PASSWORD`, nicht
|
||||
bare `PASS`). **Rotation fällig** — Google App-Passwort widerrufen + Stack-174-Env nachziehen.
|
||||
- ⚠️ **Toter Orphan:** `~/dev/homelab-cline/n8n-mcp-deploy/` (kein Git) kann gelöscht werden — ein
|
||||
erneutes `docker compose up` dort würde sonst einen Namenskonflikt mit dem Stack-174-Container
|
||||
erzeugen. Nicht kritisch (nur bei Handstart).
|
||||
- ⚠️ **Client-401 in THIS Claude-Code-Session:** der n8n-mcp-Server kam in dieser Session mit
|
||||
`AUTH_HEADER_REJECTED` (401) hoch — das ist ein **Client-Config-Thema** (`~/.claude.json`-Bearer
|
||||
leer/falsch, vgl. globale CLAUDE.md „kein Shell → `{env:}` leer"), **nicht** der hier gefixte
|
||||
Server. Der Server antwortet LAN-direkt korrekt; opencode ist unbetroffen.
|
||||
|
||||
## Auswirkung auf TP10
|
||||
Keine für den Feature-Pfad: TP10 läuft über **Cloudflare Worker Cron**, nicht über n8n. Der Fix
|
||||
macht n8n-mcp aber wieder als **Werkzeug** nutzbar (n8n-Workflow-Validierung, künftig optional
|
||||
TP10-als-n8n-Workflow). Rückantwort ans zuweisende Projekt:
|
||||
`~/dev/blaueblueten-n8n/docs/rueckantwort-n8n-mcp-fix-20260901.md`.
|
||||
130
docs/handoff-20260901-tp16.3-paragraph5-flip-durch.md
Normal file
130
docs/handoff-20260901-tp16.3-paragraph5-flip-durch.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Handoff — TP16.3 §5 durch: alle vier Namen auf `bf-public`, plus ein 10-Sekunden-Fund
|
||||
|
||||
> **2026-08-31/09-01.** Nachfolger von
|
||||
> [`handoff-20260831-tp16.3-paragraph2-3-durch.md`](handoff-20260831-tp16.3-paragraph2-3-durch.md).
|
||||
> **Nicht** Teil dieser Session: §6 (Abbau).
|
||||
|
||||
---
|
||||
|
||||
## 1. Was jetzt steht
|
||||
|
||||
**Alle vier öffentlichen Namen laufen über `bf-public`** — der öffentliche Verkehr geht damit
|
||||
erstmals über **Caddy** statt an ihm vorbei.
|
||||
|
||||
| Name | Nachweis von außen | Origin bewiesen? |
|
||||
|---|---|---|
|
||||
| `gitea` | 200, `i_like_gitea`-Cookie = echte Gitea-Antwort | ✅ |
|
||||
| `hass` | 200 + `manifest.json` 200 + **WebSocket `101 Switching Protocols`** | ✅ inkl. Companion-App-Pfad |
|
||||
| `vw` | `/`, `/alive`, `/api/config` je 200; WS-Hub `401` **von Vaultwarden** | ✅ |
|
||||
| `n8n` | 302 zum Access-Login (vor *und* nach dem Flip) | ❌ — vom User im Browser bestätigt |
|
||||
|
||||
Antwortzeiten vorher/nachher unverändert ⇒ **Caddy im Pfad kostet nichts Messbares.**
|
||||
🚫 **Die drei Alttunnel stehen bewusst weiter** (`bf-mm`/`bf-nas`/`bf-pve`, je healthy/8) — sie sind
|
||||
die Rückfallebene. Rückweg je Name = ein `PATCH` auf die alte Tunnel-ID.
|
||||
|
||||
**Schicht davor, ebenfalls durch:** die sechs AP-Drifts sind ins Soll gehoben, **Compliance 139/140**
|
||||
(28 Regeln × 5 Geräte). Übrig bleibt genau `crs326-core`/`wifi-security` = offene Transaktion
|
||||
`TP25-fund-e-ft-over-ds`. Neu: ComplianceRule **`interface-veth`** + zwei `ConfigReplace`-Regeln, die
|
||||
die gerätevergebenen veth-MACs normalisieren (`nautobot/ingest-veth-rule.py`).
|
||||
|
||||
---
|
||||
|
||||
## 2. 🔴 Der eigentliche Fund der Nacht: ein 10-Sekunden-Zoll auf drei Diensten
|
||||
|
||||
`gitea` hing bei ~10 % der Anfragen **exakt 10,1 s** — quer über Web-UI, `/api/healthz` **und** den
|
||||
Git-Pfad. **Ursache:** MariaDB (LXC **302**) hatte `skip-name-resolve` auskommentiert und machte bei
|
||||
**jeder neuen Verbindung** einen Reverse-Lookup, während ihr `/etc/resolv.conf` auf den **toten**
|
||||
`10.40.41.254` zeigte. Gemessen: **10.010 ms je Lookup**.
|
||||
|
||||
**An derselben DB hängen `Vaultwarden` (.127), `Home Assistant` (.105) und `gitea` (.157)** —
|
||||
über die Verbindungstabelle belegt.
|
||||
|
||||
**Fix (User-Freigabe, Wartungsfenster):** `pct set <id> --nameserver 10.40.20.1` + Reboot für
|
||||
`302 mariadb`, `102 mqtt5`, `106 influxdb2`, `107 redis`, `150 iob-exposed`.
|
||||
**Nachher: Lookup 21–24 ms; gitea 0 von 25 Proben langsam**, langsamste 75 ms.
|
||||
|
||||
✅ **Beseitigt 2026-09-01:** `skip-name-resolve` aktiviert (Drop-in
|
||||
`/etc/mysql/mariadb.conf.d/90-skip-name-resolve.cnf`, `@@skip_name_resolve=1`). `mysql.user` vorher
|
||||
geprüft — **kein Hostname-Grant**, alle `%`/IP/`localhost`, also gefahrlos. Wirkung: gitea/vw/hass
|
||||
je 0 von 12 frischen Anfragen langsam, max 0,25 s. Der Reverse-Lookup ist damit nicht mehr schnell,
|
||||
sondern **abgeschafft**.
|
||||
🔴 **Dabei ist das root-DB-Passwort ins Transkript geraten** (`.my.cnf` mit `password <wert>` ohne `=`,
|
||||
Maskierung ankerte auf `=`) — **TP30 Posten #6**, zu rotieren. Ausserdem: **LXC 302 war 100 % voll**,
|
||||
`+30G` online ⇒ 95 GB / 69 %; die Ursache (HA-Recorder, 41 GB `states`) ist **TP40**.
|
||||
|
||||
---
|
||||
|
||||
## 3. ✅ Latenter Fund — gefunden UND behoben: vier Container überlebten keinen Reboot sauber
|
||||
|
||||
`networking.service` und `ifupdown-wait-online.service` sind in **`101`, `102`, `106`, `107`**
|
||||
fehlgeschlagen. Folge: alles mit `After=network-online.target` startet nach einem Reboot **nicht** —
|
||||
**influxdb2 kam nicht hoch**, Unit `enabled`, **kein Startversuch im Journal**. Von Hand sofort ok.
|
||||
|
||||
🔑 **Nicht von dieser Session verursacht:** `101` wurde vor dem Fix nie angefasst und zeigte dieselben
|
||||
Units. Die Container liefen nur 13+ Tage ohne Neustart, deshalb war es unsichtbar.
|
||||
|
||||
✅ **Behoben 2026-09-01.** **Ursache — dieselbe Altlast wie beim Resolver:** tote `auto`-Stanzas in
|
||||
`/etc/network/interfaces` aus dem **alten VLAN1-Schema** (`eth0` → `10.40.41.x`) und aus früheren
|
||||
Versuchen (`veth16`, `veth24`, Tippfehler `eth01`), alle auf **nicht existierende** Interfaces.
|
||||
`ifup -a` scheiterte daran, während `veth20` sauber hochkam. Entfernt wurden ausschliesslich Stanzas,
|
||||
deren Interface in `ip -br link` fehlt; Backup je Container `/etc/network/interfaces.bak-20260901`.
|
||||
🔴 **Abnahme war ein echter Reboot, nicht der Servicestatus:** `106` neu gestartet ⇒ **influxdb kam
|
||||
nach 5 s von selbst hoch**, `networking active`, null fehlgeschlagene Units.
|
||||
Endstand: **alle 13 LXCs auf `dns=10.40.20.1`, `networking` überall sauber.** Rest ohne Netzbezug:
|
||||
`run-rpc_pipefs.mount` (101, 150), `proxmox-regenerate-snakeoil.service` (108).
|
||||
|
||||
---
|
||||
|
||||
## 4. Drei Messfallen, die diese Session Zeit gekostet haben
|
||||
|
||||
1. **Split-Horizon:** der Haus-Resolver liefert für alle vier Namen direkt `10.40.20.40` — ein Test
|
||||
von zuhause sieht Cloudflare **nie**. Prüfen nur mit `curl --resolve <name>:443:188.114.96.10`
|
||||
oder von außerhalb. *(Guter Nebeneffekt: ein misslungener Flip bricht intern nichts.)*
|
||||
2. **Access antwortet je nach Standort verschieden:** `n8n` aus dem Haus 200 (`bf4`-Policy),
|
||||
von außen 302. `hass`/`vw`/`gitea` stehen auf **`bypass`** — dort **nie** ein Login.
|
||||
⚠️ Die App `hass, vw, gitea` heisst **zu Recht** so: sie führt alle drei in `self_hosted_domains`,
|
||||
das Feld `domain` zeigt nur den ersten. Ein Rename wäre eine Verschlechterung gewesen.
|
||||
3. 🔴 **„Der Host ist ausgefallen" war der eigene Standortwechsel.** Ping/SSH/Caddy waren tot, weil
|
||||
die Session-Maschine auf einen **Hotspot** gewandert war (`route -n get default` = `172.20.10.1`).
|
||||
Daraufhin wurde ein **bereits erfolgreicher `n8n`-Flip grundlos zurückgerollt**.
|
||||
**Merkregel: vor jeder Ausfallmeldung die eigene Default-Route lesen.**
|
||||
|
||||
Dazu zwei Werkzeug-Befunde: **der Zähler der Blocker-B-Firewallregel taugt nicht als Wegbeweis**
|
||||
(cloudflared hält die Origin-Verbindung offen ⇒ kaum neue Verbindungen ⇒ Zähler steht still, obwohl
|
||||
alles läuft; richtig ist die **Verbindungstabelle**), und **Caddy führt gar kein Access-Log** ⇒ der
|
||||
alte §5.3-Punkt „Caddy sieht den Request" konnte nie funktionieren.
|
||||
|
||||
---
|
||||
|
||||
## 5. Nächste Schritte
|
||||
|
||||
1. **§6 Abbau** — sechs Container + drei Alttunnel. Frühestens nach störungsfreiem Betrieb;
|
||||
Christoph hat den **Flip** vorgezogen freigegeben, **nicht** den Abbau.
|
||||
🚫 `terpene-cloudflared` (LXC 400) und `fm.emsenhuber.net` bleiben. **Namen lesen, nicht Zeilen zählen.**
|
||||
2. **TP39** (angelegt 2026-09-01, User-Okay) fasst die zwei Restpunkte aus §2 und §3 zusammen:
|
||||
`skip-name-resolve` auf der MariaDB (vorher `mysql.user` gegen Hostname-Grants prüfen, DB-Zugang
|
||||
fehlt). **Punkt 2 (`networking.service`) ist am 2026-09-01 bereits erledigt** — offen bleiben
|
||||
`skip-name-resolve` und der Resolver-Sweep als **wiederkehrende** Kontrolle, auch über die
|
||||
NAS-Container.
|
||||
3. **TP30:** Nautobot-Tokens (#5) + **MariaDB-root-Passwort (#6, neu 09-01)** rotieren.
|
||||
4. **TP40:** HA-Recorder-Retention — die 41-GB-`states`-Tabelle beschneiden (angelegt 09-01).
|
||||
5. **TP14.4:** ohne Service-Token für die Wildcard-App ist `n8n` von außen nicht bis zum Origin prüfbar.
|
||||
6. **Caddy-Access-Log** (TP31/TP34): der öffentliche Reverse Proxy protokolliert keine Requests.
|
||||
7. `mcp/mikromcp/config/routers.yaml` meldet weiter `rosVersion: "7.24"`, live ist `7.24.1`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Nachtrag 2026-09-01 abends: §6 Abbau vorgezogen und durch — TP16.3 GESCHLOSSEN
|
||||
|
||||
Der User zog §6 vor („es wird nichts mehr sein"). Reihenfolge Container→Tunnel eingehalten.
|
||||
- **7 Container entfernt:** die sechs BF-cloudflared (LXC 400 / macmini / NAS ep14) **plus
|
||||
`terpene-cloudflared`** — Letzterer auf zusätzlichen Entscheid, weil `420.teilzeitladen.xyz` jetzt
|
||||
über Caddy/CF läuft. Kein Stack dahinter.
|
||||
- **Beweis vor der Tunnel-Löschung:** `420.teilzeitladen.xyz` lieferte mit bereits entferntem
|
||||
`terpene-cloudflared` echten Origin-Inhalt (assetlinks-JSON, 200).
|
||||
- **4 Tunnel gelöscht:** `bf-mm`, `bf-nas`, `bf-pve`, `terpene-db` (jede ID gegen die Behalten-Liste
|
||||
`bf-public`/`fm` geprüft).
|
||||
- **Schlusskontrolle:** nur noch `bf-public` (12) + `fm` (4) healthy; alle vier BF-Namen und `420`
|
||||
weiterhin 200.
|
||||
|
||||
**TP16.3 ist damit vollständig abgeschlossen** (Status ✅ 2026-09-01, wandert ins Archiv).
|
||||
54
docs/handoff-20260901-tp25-ap2-verdacht.md
Normal file
54
docs/handoff-20260901-tp25-ap2-verdacht.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Handoff 2026-09-01 — TP25: Fund E geheilt (sauberes Fenster) + neuer Verdacht `ap2`
|
||||
|
||||
**Kontext:** Christoph meldete um **2026-08-31 23:02** eine WLAN-Störung am Schreibtisch (5G, iPhone,
|
||||
kein Telefonat). Diese Session hat den Vorfall am Manager `crs326-core` analysiert (alles read-only)
|
||||
und dabei den Fund-E-Stand korrigiert. Parallel wurde TP39 abgeschlossen (eigener Strang, s. Archiv).
|
||||
|
||||
## Kernbefunde
|
||||
|
||||
### 1. Fund E (`reauthenticating`) ist geheilt — die „GESCHEITERT"-Wertung war kontaminiert
|
||||
- Core-Uptime `10h41m` @ 01:18 ⇒ letzter Reboot **14:36** (TP27-Upgrade). Der `caps`-Log endet um
|
||||
15:57; um 23:02 **kein** caps-Ereignis ⇒ kein Infrastruktur-/Reboot-Burst, echtes Client-Event.
|
||||
- **Tages-Query** `get_log topics=[wireless] prefix=reauthenticating sinceMinutes=1440` → **total 0**.
|
||||
Das erste ungestörte Fenster (14:36 → 01:20, **10,7 h**) zeigt **0× reauthenticating**; Baseline 93×.
|
||||
- Die im Vorgänger-Handoff notierten „124× nach dem Eingriff" fielen in die TP27-Upgrade-Reboots
|
||||
(viele MACs = Infrastruktur, CLAUDE.md-Gotcha). ⇒ **Hebel 1 (`ft-over-ds=no`) hat sein Ziel erreicht.**
|
||||
|
||||
### 2. Neuer Teilbefund: `ap2` unterperformt (das ist der 23:02-Schmerz, NICHT FT)
|
||||
AP-Karte (Manager, stabil seit Rejoin 15:57): `cap-wifi5/6 = ap2`, `cap-wifi3/4 = ap3`,
|
||||
`cap-wifi1/2 = ap1` (funkstill).
|
||||
|
||||
- 23:02: iPhone `F2:62:4C:E1:AF:09` ping-pongt im Sekundentakt `cap-wifi5 ↔ cap-wifi6` =
|
||||
**ap2s 5G (5220) ↔ ap2s 2,4G (ch11/2462)** — Band-Steering-Thrash auf **demselben** AP.
|
||||
`disconnected, not responding` um 22:37:40 (−76) und **23:01:00** (−82). Roam-Feldstärke −75…−88 dBm.
|
||||
- 🔴 **Christophs Fakt:** iPhone ↔ ap2 nur **2 m**, gleicher Raum, ap2 auf 2,3 m. Bei 2 m wären
|
||||
−35…−45 dBm normal. −80 auf 2 m ⇒ **kein Coverage-, kein FT-Problem**.
|
||||
- **0 Clients auf ap2 aktuell**, alle 29 auf ap3 → die Clients meiden ap2.
|
||||
- Verdacht: **ap2s Funk selbst** (RF/Antenne/HW) und/oder **DTU-Störung auf ap2/ch11**
|
||||
(Transaktion `TP17.1-dtu-pin-ap2`, `54:F2:9F:12:51:F0`, −59 dBm auf ap2s 2,4-Radio).
|
||||
|
||||
**In-situ-Diagnose nötig** (nachts nicht messbar, Phone idle auf ap3): Registration-Signal live prüfen,
|
||||
während ein Client auf ap2 hängt. Kandidaten-Eingriffe: DTU-Pin lösen/verlegen; `dirtyvader-main` auf
|
||||
ap2 temporär deaktivieren (ap3 übernimmt Schreibtisch); ap2-Antenne/HW prüfen. **Keine Änderung ohne
|
||||
diese Messung.**
|
||||
|
||||
## Offen / nächster Schritt
|
||||
|
||||
**Hebel 1 committen** (Transaktion `TP25-fund-e-ft-over-ds`, Scope `wifi-security`, Ablauf 2026-09-03).
|
||||
Der Commit ist eine **git-push-Kette** und wartet auf Christophs Go:
|
||||
|
||||
1. `nautobot/mikrotik_routeros.j2` **Z. 220**: `sec-main` `ft-over-ds=yes` → `ft-over-ds=no`.
|
||||
2. Template-Repo nach Nautobot syncen (Golden-Config-Git-Repository).
|
||||
3. `python3 nautobot/gc-configplan.py --refresh-compliance` (Backup → Intended → Compliance).
|
||||
4. `python3 nautobot/gc-transaktion.py commit --change-id TP25-fund-e-ft-over-ds`
|
||||
(verweigert, solange `wifi-security` noch driftet — deshalb Schritt 1–3 zuerst).
|
||||
|
||||
🔴 Schritt 1 ist ein `git push` (Backup-Guard + Christophs Commit-Hinweis-Regel) und Schritt 2–4 sind
|
||||
Live-Nautobot-Jobs — bewusst **nicht autonom** ausgeführt. Geräte-Backup `pre-tp25-funde-ftoverds.backup`
|
||||
liegt auf dem Core. `wifi-security` wird ohnehin **nicht deployt** (Passphrasen `<<REDACTED>>` im
|
||||
Template, Z. 189–196) — der Commit ist reine Soll↔Live-Angleichung, kein Geräte-Write.
|
||||
|
||||
## Werkzeug-Notiz
|
||||
- AP-Zuordnung: `/interface wifi radio print terse proplist=cap,radio-mac,interface` am Manager.
|
||||
- reauth-Zählung: `get_log` mit `prefix=reauthenticating` (nicht `list_wifi_interfaces` — leakt PSKs).
|
||||
- Kanäle: `/interface wifi print detail` je `cap-wifiN` (Frequenz + Band im `channel.`-Block).
|
||||
109
docs/handoff-20260901-tp41-followup.md
Normal file
109
docs/handoff-20260901-tp41-followup.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Handoff 2026-09-01 — TP41 Follow-up: IdP-Feinschliff, App-Launcher, Geli-Zugänge, dw-DNS
|
||||
|
||||
> Kleine Folgesession nach TP41 (T4/T3/T2 durch). Sammelt die Rest-Punkte rund um **Logins für Geli**,
|
||||
> die **App-Launcher-Seite** und den **dw-Split-Horizon** für Terpenfinder. Mehrere Punkte sind
|
||||
> **User-Konsolen-Aufgaben** (Google/Meta), dafür je eine Kurzanleitung.
|
||||
|
||||
## Status je Punkt (Stand dieser Session)
|
||||
| # | Punkt | Stand |
|
||||
|---|---|---|
|
||||
| 1 | GitHub-Login | ✅ funktioniert (User bestätigt) |
|
||||
| 2 | Google „Zugriff blockiert: nur innerhalb der Organisation" | ✅ **gefixt** — User hat Consent-Screen auf *External* gestellt; Google-Login läuft (bestätigt 2026-09-01). Anleitung §A war der Weg. |
|
||||
| 3 | Meta/Facebook einbinden | ❌ **für TP41 abgesagt** (User-Entscheid 2026-09-01) — optional, kein Bedarf. Keine App, kein CF-IdP angelegt. Geli via OTP+Google voll gedeckt. §B nur noch als Anleitung, falls später gewünscht. |
|
||||
| 4 | Geli-Zugänge hinterlegen | ✅ `pillepalle670@gmail.com` in `zt-humans`. **FB-Konto-Mail = `angelikahy@outlook.de`** (schon drin → Facebook automatisch abgedeckt, sobald Meta läuft). Instagram = kein CF-IdP. |
|
||||
| 5 | App-Launcher überarbeiten | ✅ **D1 umgesetzt** — 3 Bookmark-Kacheln (Vaultwarden/Home Assistant/Terpenfinder), Bundle-/Wildcard-/Terpene-self_hosted-Kacheln aus dem Launcher genommen (Policies **unverändert** geprüft), Launcher gestylt (Titel „BF-Zugänge", Begrüßung, Buttons). |
|
||||
| 6 | `420.teilzeitladen.xyz` an dw | ✅ **Entscheidung:** Geli sofort per **WARP**; das dw-Site-DNS-Uplink-Thema → **TP43** (angelegt). |
|
||||
|
||||
---
|
||||
|
||||
## §A — Google-Login-Fix (User, Google Cloud Console)
|
||||
Fehler „cloudflare kann nur innerhalb der Organisation verwendet werden" = der **OAuth-Consent-Screen**
|
||||
des Google-Projekts steht auf **User Type = Internal** (nur Workspace-Org-Konten). Gelis Gmail ist extern
|
||||
→ blockiert. Fix (der CF-Google-IdP `c757…` bleibt unverändert, nur die Consent-Einstellung ändert sich):
|
||||
1. <https://console.cloud.google.com> → richtiges Projekt (das, aus dem die Google-OAuth-Client-ID stammt).
|
||||
2. **APIs & Services → OAuth consent screen** (neu: „Google Auth Platform → Audience").
|
||||
3. **User Type / Audience von *Internal* auf *External*** stellen.
|
||||
4. **Veröffentlichen:** Publishing status → **„In production"** (dann kann jedes Google-Konto rein).
|
||||
Alternativ in „Testing" bleiben und **Gelis Gmail als Test user** eintragen.
|
||||
5. Danach Login-Test mit Gelis Google-Konto. (Bei „External/unverified" kommt ggf. ein
|
||||
„unbestätigte App"-Hinweis — für den kleinen Kreis unkritisch, oder App verifizieren lassen.)
|
||||
|
||||
## §B — Meta/Facebook als Login (User legt App an, dann CF-IdP durch mich)
|
||||
Es gibt **noch keine** Facebook-App (Creds leer). Schritte:
|
||||
1. <https://developers.facebook.com> → **My Apps → Create App** → Use case **„Authenticate and request
|
||||
data from users with Facebook Login"** (Consumer).
|
||||
2. Produkt **Facebook Login** hinzufügen.
|
||||
3. **Facebook Login → Settings → Valid OAuth Redirect URIs** =
|
||||
`https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback`
|
||||
4. **App settings → Basic:** **App ID** + **App Secret** → an mich (in `~/.secrets`, **nicht** in den Chat),
|
||||
ich trage sie in `mcp/cloudflare/.env` (`FACEBOOK_APP_ID/SECRET`) ein und lege den CF-Facebook-IdP an.
|
||||
5. **App Mode → Live** (sonst dürfen nur App-Rollen/Tester rein); Geli ggf. als Tester eintragen.
|
||||
6. ⚠️ CF matcht die Policy über die **E-Mail**, die Facebook zurückgibt — diese E-Mail muss in
|
||||
`zt-humans` stehen (s. §C).
|
||||
|
||||
## §C — Geli: Zugangsmethoden (Matrix)
|
||||
CF Access matcht Personen über die **E-Mail** der Identität (nicht über Usernamen). Stand:
|
||||
| Methode | Gelis Angabe | CF-Status | To-Do |
|
||||
|---|---|---|---|
|
||||
| OTP (E-Mail-Code) | `angelikahy@outlook.de` | ✅ in `zt-humans` | — |
|
||||
| OTP + Google | `pillepalle670@gmail.com` | ✅ **heute ergänzt** | Google-Fix §A nötig, damit Google-Login geht |
|
||||
| Facebook | User `35Lika.Ange` | ⏳ | Facebook-App (§B); dann die **E-Mail** ihres FB-Kontos in `zt-humans` — welche ist das? (vermutlich eine der beiden obigen) |
|
||||
| Instagram | `angelikahy` | ❌ **CF Access hat keinen Instagram-IdP** | Nicht möglich als Direkt-Login → Geli nutzt Facebook/Google/OTP |
|
||||
|
||||
→ Sobald Gelis FB-Konto-E-Mail bekannt ist und sie eine der schon hinterlegten Adressen ist, ist Facebook
|
||||
automatisch abgedeckt. Sonst diese E-Mail zusätzlich in `zt-humans` aufnehmen.
|
||||
|
||||
## §D — App-Launcher `emsenhuber.cloudflareaccess.com` überarbeiten
|
||||
**Ist-Analyse (live):** Der Launcher (App `6df5c431`, `landing_page_design={}` = ungestylt) zeigt Kacheln
|
||||
aus den Access-Apps mit `app_launcher_visible=true`:
|
||||
- `1dbc45ca` **„hass, vw, gitea"** (self_hosted, Domain `vw.emsenhuber.net`) → **eine** Kachel, verlinkt nur vw.
|
||||
- `16aaec78` **`*.emsenhuber.net`** (Wildcard) → Kachel ohne sinnvolles Ziel.
|
||||
- `e6a7991f` **Terpenfinder v3** (`420.teilzeitladen.xyz`) → eigene Kachel ✅.
|
||||
Deshalb „stimmt nicht mehr": vw/hass/gitea teilen sich eine Kachel, die Wildcard-Kachel stört.
|
||||
|
||||
**Ziel:** je ein sauberer Button für **Vaultwarden, Home Assistant, Terpenfinder** + freundlichere Seite.
|
||||
**Zwei Wege (Entscheidung offen):**
|
||||
- **D1 — CF-nativ (empfohlen, „diese Seite"):** je ein **Bookmark-App** (type `bookmark`) für vw/hass/
|
||||
terpenfinder mit Name + Logo (eigene Kachel/Link), die Wildcard-Kachel aus dem Launcher nehmen,
|
||||
`landing_page_design` setzen (Titel z.B. „BF-Zugänge", Begrüßung, Farbe, Logo). Reversibel, in Minuten.
|
||||
Grenze: CF-Styling = Titel/Text/Farbe/Logo + uniforme Kacheln.
|
||||
- **D2 — Custom-Landing-Page:** eigene HTML-Seite (Caddy, hinter Access) mit voller Gestaltung/großen
|
||||
Buttons. Mehr Design, mehr Aufwand (eigener vhost + Access-Regel).
|
||||
|
||||
## §E — dw: `420.teilzeitladen.xyz` lokal auflösen (FritzBox `10.95.10.1`)
|
||||
**Ehrliche FritzBox-Antwort:** Eine FritzBox kann **keinen** freien „Hostname → beliebige IP"-Override im
|
||||
GUI (nur *DNS-Rebind-Schutz-Ausnahmen* = Whitelist gegen Rebind-Blockade, **ohne** IP-Zuweisung). Ein
|
||||
sauberer Split-Horizon für genau diesen Namen braucht daher einen **kleinen lokalen Resolver** am dw
|
||||
(dnsmasq/AdGuard/Pi-hole auf einem Dauerläufer): `address=/420.teilzeitladen.xyz/<BF-Caddy-über-WG>` +
|
||||
Rest weiterleiten; diesen Resolver als DNS der FritzBox bzw. der Clients setzen.
|
||||
⚠️ **Vor Umsetzung verifizieren** (nicht aus dem Kopf): FritzOS-Version am dw + ob ein Dauerläufer da ist.
|
||||
**BF-seitige Prereqs (fehlen noch):**
|
||||
1. **Caddy-vhost** `420.teilzeitladen.xyz` → macmini-Worker (`10.40.20.167:8890`) **mit Cert**
|
||||
(DNS-01, `…4148` hat jetzt teilzeitladen.xyz-DNS).
|
||||
2. **WG-Route** dw → `10.40.20.40` (Caddy) muss stehen.
|
||||
3. **Split-Horizon** für `420.teilzeitladen.xyz` (heute liefern auch `.36/.37` **public** für diesen Namen).
|
||||
Cross-Projekt (teilzeitladen.xyz). Alternative aus Ur-Handoff: Gelis Gerät in **WARP** (Session statt Login,
|
||||
CGNAT unkritisch) + Access-Policy auf die WARP-Identität — spart den ganzen dw-DNS-Umbau.
|
||||
|
||||
## Entscheidungen (2026-09-01, getroffen)
|
||||
1. **App-Launcher:** ✅ **D1** (CF-nativ) — umgesetzt (s. §D / Punkt 5).
|
||||
2. **Gelis Facebook-Mail:** ✅ `angelikahy@outlook.de` — schon in `zt-humans`, Facebook damit abgedeckt.
|
||||
3. **dw-Ansatz:** ✅ Geli per **WARP** (sofort); Site-DNS-Uplink als **TP43** ausgelagert.
|
||||
|
||||
## Verbleibende offene To-Dos (User)
|
||||
- ~~**§A Google-Consent-Screen** auf *External*~~ ✅ **erledigt** — Google-Login läuft (2026-09-01).
|
||||
- ~~**§B Facebook-App anlegen**~~ ❌ **abgesagt für TP41** (User-Entscheid 2026-09-01) — optional; §B
|
||||
bleibt als Anleitung stehen, falls später doch gewünscht.
|
||||
- ~~**d47435-Revoke**~~ ✅ erledigt · ~~**T3-WARP-Client-Verify**~~ ✅ ok (User, 2026-09-01).
|
||||
- **Geli in WARP:** ✅ **CF-seitig nichts zu tun** — Enrollment läuft über App „Warp Login App"
|
||||
(`6c32fe23…`) → `bf-users` → Gruppe `zt-humans`, die Gelis Mails **schon enthält**; sie darf bereits
|
||||
enrollen. Terpenfinder-`geli`-Policy lässt sie per E-Mail durch. **Rest = Handgriff auf Gelis Gerät:**
|
||||
WARP installieren, Team `emsenhuber`, Login OTP `angelikahy@outlook.de` oder Google `pillepalle670@gmail.com`.
|
||||
*Permission-Frage:* CF-seitig keine nötig; `/access/seats` per MCP nicht nutzbar (`10405`, Endpoint will
|
||||
User-Token statt Account-Token — kein Scope-Fix, für Enroll irrelevant).
|
||||
- **T5 (TP41)** ✅ GitHub- **und** Google-Login laufen (bestätigt).
|
||||
- **TP43** (dw-Site-DNS) bei Gelegenheit.
|
||||
|
||||
> **TP41-Auth-Kern damit abgeschlossen (2026-09-01):** T2/T3/T4/T5 ✅, FB abgesagt, d47435-Revoke ✅,
|
||||
> WARP-Verify ✅, Geli CF-seitig fertig. **Nichts mehr auf Claude-/CF-Seite offen** — verbleibt nur
|
||||
> Gelis WARP-Client auf ihrem Gerät.
|
||||
166
docs/handoff-20260901-tp41.md
Normal file
166
docs/handoff-20260901-tp41.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Handoff 2026-09-01 — TP41 CF-Access-Reparatur + Zero-Trust-Konsolidierung
|
||||
|
||||
> **Branch `tp41-cf-access-repair`.** Alle CF-Änderungen sind **live via API** gemacht (Schreibpfad
|
||||
> `CF_API_TOKEN` + curl, cf-tunnel-mapping.md §11). Working-Tree: `docs/cf-backup/tp41-20260901/`
|
||||
> (Snapshots, secret-frei) + dieser Handoff + `teilprojekte.md`-Eintrag; `mcp/cloudflare/.env`
|
||||
> (gitignored) wurde geändert (Token-Konsolidierung). Helper-Skripte lagen im Scratchpad/`/tmp`
|
||||
> (`cf_session.py`, `cf_harden.py`, `cf_groups.py`, `cf_vwadmin.py`, `cf_carveout.py`, `t4a.py`).
|
||||
|
||||
## Auslöser
|
||||
Zugriff auf CF-geschützte Apps zwang Christoph **und Geli** faktisch **täglich** zum E-Mail-OTP-Login,
|
||||
obwohl 30 Tage gelten sollten; föderierte Logins (GitHub/Google) „funktionieren nicht". Root-Causes:
|
||||
(1) **Team-Domain-Rename `bf4` → `emsenhuber`** ⇒ Provider-OAuth-Apps kennen die neue Callback-URL nicht;
|
||||
(2) App-**Session 24h**; (3) diverse Ordnungs-/Sicherheitslecks. Daraus wurde eine
|
||||
Zero-Trust-Konsolidierungs-Runde.
|
||||
|
||||
## ✅ LIVE erledigt (verifiziert)
|
||||
- **Session 720h** auf Wildcard (`16aaec78`), vw-App (`1dbc45ca`), Warp-Login (`6c32fe23`).
|
||||
- **login_method-Loch geschlossen:** reusable Policy **`bf-users` (`4ccc9b7e`)** = `allow` mit **nur**
|
||||
`email:christoph@emsenhuber.com` + `email:<geli>@outlook.de` (kein `login_method`-Include mehr).
|
||||
Attached an Wildcard / App-Launcher (`6df5c431`) / Warp-Login. Reusable Policy `8e44f5d1`
|
||||
**entkoppelt** → hängt jetzt **nur noch an Terpenfinder** (Fremdprojekt, nicht angefasst).
|
||||
- **Access-Gruppen (Prefix `zt-`):** `zt-humans` (`6eeec7f3`, christoph+geli), `zt-home`
|
||||
(`c0f8ba0d`, IP `90.146.33.177/32`), `zt-automation` (`1b60b608`, svc-token `65f1821a`).
|
||||
Policies `bf-users` / `bf4` (`5165d139`) / `claude-mcp` (`39fe0e9d`) zeigen jetzt **auf die Gruppen**
|
||||
→ Personen-/IP-/Token-Pflege künftig nur noch in der Gruppe.
|
||||
- **vw = voll Bypass** (Passwort-Lebensader: Web-Vault + Bitwarden-App/Extension/Desktop offen, **kein**
|
||||
CF-Login davor). Ein Carve-out-Versuch (nur Client-Pfade bypass, Rest gaten) wurde **verworfen**:
|
||||
CF-**Bypass kurzschließt** spezifischere path-Apps, und `/` (Web-Vault-Root) teilt den Prefix mit
|
||||
`/admin` — nicht trennbar. Die 3 Experiment-Apps wurden wieder gelöscht.
|
||||
- **`vw.emsenhuber.net/admin` öffentlich geblockt** per **WAF-Custom-Rule** (Zone-Ruleset
|
||||
`416af72d0dd54853805875bf5752afd7`, Regel `f26744eb…`, `action=block`,
|
||||
expr `http.host eq "vw.emsenhuber.net" and (path eq "/admin" or starts_with(path,"/admin/"))`).
|
||||
**Verifiziert über CF-Edge** und vom User per **Mobilfunk** („you have been blocked"). Lokal (Heim-LAN,
|
||||
Split-Horizon → Caddy) und später WARP-intern bleibt `/admin` erreichbar.
|
||||
- **API-Token konsolidiert:** `mcp/cloudflare/.env` `CF_API_TOKEN` = **`…4148`** (id `493ed8bd…`),
|
||||
Backup `mcp/cloudflare/.env.bak-tp41-20260901`. Der User hat `…4148` anschließend **vollständig**
|
||||
gemacht (u.a. **Access: Service Tokens Write** + **Zero Trust Write** + WAF + Groups + DNS für
|
||||
emsenhuber.net **und** teilzeitladen.xyz). **Altes Token `…2174` (id `9984078812bc18d4ebb6a64b570144f2`)
|
||||
ist am 2026-09-01 vom User revoked ✅.**
|
||||
|
||||
> ⚠️ **API-Token-Altlast → ARBEITSPAKET für die Folgesession (User 2026-09-01):** der User fand ein
|
||||
> weiteres API-Token **`b00722522c685920f73cfcc62e9555d9`** mit **exakt denselben Permissions wie
|
||||
> `d47435d5c86b764bbf7c5b19ae827033`** — vermutlich eine **blaueblüten/Terpene-Altlast**.
|
||||
> **Auftrag: Projekte nachziehen** — feststellen, welcher Consumer welches der beiden Tokens nutzt,
|
||||
> auf **eines** konsolidieren, das verwaiste dann abbauen. Token-/Credentials-Hygiene (TP30-nah).
|
||||
|
||||
## 🔜 OFFEN (Token reicht jetzt für alles außer T5)
|
||||
- **T4 — kumulatives Service-Token `zt-svc`** (Basis: `t4a.py`, war nur an fehlender Perm gescheitert):
|
||||
1. `claude-mcp` (`65f1821a`) **rename → `zt-svc`** + **rotate** (Secret einmalig).
|
||||
2. `terpene-svc`-Policy (`bf7d2e5e`) **additiv** += group `zt-automation` (akzeptiert dann alt **und** neu).
|
||||
3. Secret ablegen: `mcp/cloudflare/.env` (`CF_ACCESS_CLIENT_ID/SECRET`) **und**
|
||||
`~/.secrets/credentials.env` — dort auch die Terpene-Aliase **`TERPENE_ACCESS_CLIENT_ID/SECRET`**
|
||||
(die die Tools lesen) **und** `TERPENE_VERIFY_CF_CLIENT_ID/SECRET` (beide zeigten auf terpene-verify-v2).
|
||||
4. **Verify Terpene:** `python3 ~/dev/blaueblueten-n8n/tools/test_whoami.py`
|
||||
(→ `420.teilzeitladen.xyz/api/admin/whoami`, muss weiter funktionieren).
|
||||
5. Erst **nach** grünem Verify: `terpene-verify-v2` aus `terpene-svc` entfernen, dann
|
||||
**`terpene-verify` (`a6be7efa`) + `terpene-verify-v2` (`1082bad1`) löschen**.
|
||||
6. `~/.secrets/README.md`-Index nachziehen. opencode/`exports.zsh` optional (gui-env-sync).
|
||||
→ End: **ein** Service-Token `zt-svc` über Gruppe `zt-automation` in allen Apps + Consumern.
|
||||
- **T3 — WARP löst `emsenhuber.net` intern auf** (User-Wahl „Variante 2"): WARP-Device-Profile
|
||||
`fallback_domains` += `emsenhuber.net` → interner Resolver **`10.40.20.1`** (liefert Split-Horizon
|
||||
`*.emsenhuber.net` → Caddy `10.40.20.40`). Route **`10.40.0.0/16` existiert** (tunnel `d1da7c8a`).
|
||||
Danach `/admin` + alle internen Namen über **WARP** via Caddy erreichbar (kein CF/WAF). ⚠️ **account-/
|
||||
profilweit** → als Lifecycle-Change **proaktiv melden**. (Token hat jetzt Zero-Trust-Write.)
|
||||
- **T2 — 404 statt 403 (User-Wunsch):** WAF-**Custom-Response ist Free-Plan-gesperrt** („not entitled to
|
||||
use a custom response"). 403-Block bleibt — außer man macht es **Origin-seitig in Caddy** (`respond 404`
|
||||
wenn Header `CF-Connecting-IP` gesetzt = via CF gekommen; lokal/WARP-intern ohne Header → durchlassen).
|
||||
Das komponiert sauber mit T3 (WARP-intern trifft Caddy ohne CF-Header). Eigener Caddy-Deploy (LXC 130).
|
||||
- **T5 — IdP-Konsolen (USER-Hausaufgabe, DER Daily-OTP-Fix, bestätigt kaputt):** User-Test lieferte
|
||||
GitHub **„The redirect_uri is not associated with this application"**. Fix in den **Provider-Konsolen**:
|
||||
- **GitHub** OAuth-App `Ov23li2h96hAkGRPJXYV` → *Authorization callback URL*
|
||||
- **Google** OAuth-Client → *Authorized redirect URIs*
|
||||
- beide = **`https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback`**.
|
||||
Danach Login-Test je Provider; Gegenprobe CF-Audit `GET /accounts/…/access/logs/access_requests`
|
||||
(`identity_provider=github/google` statt `onetimepin`).
|
||||
- **T6 (optional) — Rate-Limit:** vw `/identity/connect/token` + gitea-Login. **Kein** Managed-Challenge
|
||||
vor vw-API/`/identity`, git-/api-Pfaden, `assetlinks.json` (bricht Bitwarden-Clients / git / MCP).
|
||||
- **T7 — Doku:** ggf. `docs/tp41-cf-access-repair-runbook.md` (Detail-Runbook) ergänzen.
|
||||
|
||||
## 🆕 NEU — dw/Geli an der Auth vorbei (Terpenfinder, CGNAT)
|
||||
Ziel: dw erreicht `420.teilzeitladen.xyz` **ohne** CF-Login. IP-Bypass wie `bf4` scheitert an Gelis
|
||||
**CGNAT**. **Eleganteste Lösung (User-Idee): Split-Horizon am dw-Standort** — dw-FritzBox setzt lokalen
|
||||
DNS-Override `420.teilzeitladen.xyz` → BF-Caddy (`caddy-bf1` / `10.40.20.40`), erreichbar über den
|
||||
bestehenden **WG-Tunnel dw↔core**; Caddy braucht einen Block `420.teilzeitladen.xyz` → macmini-Worker
|
||||
(`10.40.20.167:8890`) **mit Cert** (DNS-01; Token hat jetzt DNS-Write für `teilzeitladen.xyz`).
|
||||
Vorab prüfen: (a) FritzBox-Host-Override möglich; (b) WG-Route dw→10.40.20.40; (c) Worker wirklich auf
|
||||
`macmini:8890` von Caddy erreichbar. **Cross-Projekt** (teilzeitladen.xyz). Alternative: Geli-Gerät in
|
||||
**WARP** (Session statt Login, CGNAT unkritisch) + Access-Policy auf WARP-Identität.
|
||||
|
||||
## ❓ Scope-Klärung für die neue Session
|
||||
Der User nannte „TP3/TP4/TP5 gleich mitnehmen" — **diese sind laut `teilprojekte.md` abgeschlossen**
|
||||
(TP3 WLAN-Rebuild ✅, TP4 ap1-Router/WAN-Edge ✅, TP5 deny-by-default ✅). Vermutlich Zahlendreher.
|
||||
**Offene Kandidaten:** TP6 (CAKE, Projektziel), TP16.1 (WARP-Mesh nativ), TP16.3, TP24 (DC-USV),
|
||||
TP25 (WLAN-Signal/Re-Walk). **Vor Start klären, welche gemeint sind** (je eigene Session empfohlen;
|
||||
Subagenten nur für parallele, abgegrenzte Teilaufgaben innerhalb einer Session).
|
||||
|
||||
## 🧭 Test-Vantage-Lehre (wichtig, hat hier Stunden gekostet)
|
||||
Von der **Heim-IP** löst `*.emsenhuber.net` → `10.40.20.40` (Caddy) und **umgeht CF komplett** — CF-Access/
|
||||
WAF-Gating ist von zuhause **nicht** sichtbar (alles wirkt „offen"). Edge-Verhalten **erzwingen** mit
|
||||
`curl --resolve <host>:443:<CF-anycast-IP>` (CF-IP via `dig @1.1.1.1 +short <host>`). **WebFetch ist für
|
||||
Access/Redirects unzuverlässig** (erreichte Origin trotz Gating) — **nicht** als Beweis verwenden; echter
|
||||
Remote-Test = User-Gerät im Mobilfunk.
|
||||
|
||||
## Referenz-IDs
|
||||
Apps: Wildcard `16aaec78` · vw/hass/gitea-Bundle `1dbc45ca` · App-Launcher `6df5c431` · Warp-Login
|
||||
`6c32fe23` · Terpenfinder v3 `e6a7991f`. Policies: `bf-users` `4ccc9b7e` · `bf4` `5165d139` · `claude-mcp`
|
||||
`39fe0e9d` · `terpene-svc` `bf7d2e5e` · (Terpene-only) `8e44f5d1`. Gruppen: `zt-humans` `6eeec7f3` ·
|
||||
`zt-home` `c0f8ba0d` · `zt-automation` `1b60b608`. Service-Tokens: `claude-mcp`→`zt-svc` `65f1821a` ·
|
||||
`terpene-verify` `a6be7efa` (Waise) · `terpene-verify-v2` `1082bad1`. WAF: Ruleset `416af72d…`, Regel
|
||||
`f26744eb…`. Team-Domain `emsenhuber.cloudflareaccess.com` (Org-`name`-Altlabel `bf4…` nicht anfassen).
|
||||
|
||||
---
|
||||
|
||||
## ✅ Update — Folgesession 2026-09-01 (T4 durch, Token-Altlast geklärt, Drift-Korrekturen)
|
||||
|
||||
### T4 — zt-svc ✅ DURCH (Variante B, inkl. Worker)
|
||||
- `claude-mcp` (`65f1821a`) → **`zt-svc`** umbenannt **und rotiert** (Secret in
|
||||
`mcp/cloudflare/.env` `CF_ACCESS_CLIENT_ID/SECRET` + `~/.secrets/credentials.env`; dort
|
||||
`TERPENE_ACCESS_*` und `TERPENE_VERIFY_CF_*` jetzt = zt-svc). client_id
|
||||
`ad1b47dee8ba9625eebb30247d163dda.access`.
|
||||
- **Worker-Pin gefunden** (`blaueblueten-n8n/worker/src/index.js:44`): Admin wird nur dem Token mit
|
||||
`common_name == env.TERPENE_SVC_CLIENT_ID` gewährt. Deshalb Variante B: **`wrangler secret put
|
||||
TERPENE_SVC_CLIENT_ID`** = zt-svc-client_id (wrangler-OAuth-Session, `workers_scripts:write` — die
|
||||
„Deploy blockiert"-Notiz galt nur für API-Tokens). Kein Code-Redeploy nötig.
|
||||
- `terpene-svc` (`bf7d2e5e`) include = **nur noch Gruppe `zt-automation`** (`1b60b608`).
|
||||
**`terpene-verify` (`a6be7efa`) + `terpene-verify-v2` (`1082bad1`) gelöscht.** Einziges verbleibendes
|
||||
Access-Service-Token = **`zt-svc`**. Verify: `test_whoami.py` → `admin:true`, common_name = zt-svc. ✅
|
||||
|
||||
### Token-Altlast (b00722 / d47435) — GEKLÄRT (Rollen waren im Ur-Handoff vertauscht)
|
||||
- **`b00722`** ist **NICHT** die Altlast, sondern das **LIVE** von Caddy genutzte DNS-01-Token
|
||||
(LXC130 `/etc/caddy/caddy.env`, SSoT). Certs valide bis Nov 2026.
|
||||
- **`d47435`** = **stale Klartext-Kopie** in `credentials.env` (gleiche Perms, kein Live-Consumer).
|
||||
n8n hält **0 Credentials**, blaueblüten hält keinen der beiden. `credentials.env`-Kopie am
|
||||
2026-09-01 auf **b00722** realignt (SSoT-Abgleich).
|
||||
- 🔜 **USER-Aktion:** **`d47435` revoken** (Dashboard oder `…4148` kurz „Account API Tokens Write"
|
||||
geben — `…4148` kann API-Tokens weder listen noch revoken, Bestätigung 9109/1000).
|
||||
|
||||
### Drift-Korrekturen (live gemessen)
|
||||
- **T3-Resolver:** interner Split-Horizon liegt auf **`10.40.20.36`/`.37`** (→ `*.emsenhuber.net = .40`),
|
||||
**nicht** auf `10.40.20.1` (der liefert public CF). T3-fallback_domains müssen auf `.36/.37` zeigen.
|
||||
- **`10.40.20.16/.17`** (AdGuard laut CLAUDE.md) sind **stale** → neu als **TP42** angelegt
|
||||
(`docs/handoff-20260901-tp42-naming.md`): `.bf.lan`/`.bf.emsenhuber.net`-Vereinheitlichung.
|
||||
|
||||
### 🔴 Leak (Transparenz)
|
||||
Beim maskierten Lesen von `credentials.env` ist der Wert **`TERPENE_ANDROID_KEYSTORE_PW`** ins
|
||||
Sitzungstranskript geraten (Regex-Loch `_PW`). **Rotation erwägen** (Terpene-Android-Signing).
|
||||
|
||||
### T3 — WARP-intern ✅ APPLIED (2026-09-01)
|
||||
- Ziel-Profil geklärt: das custom „Cloudflare Mesh"-Profil matcht **nur** `warp_connector@…` → Christoph/Geli
|
||||
laufen im **Default-Profil** (`0197d1b3`). `fallback_domains += emsenhuber.net → [10.40.20.36, 10.40.20.37]`
|
||||
dort gesetzt (15 Suffixe). Tunnel-Route `10.40.0.0/16` via `d1da7c8a` existiert; Exclude-Liste enthält
|
||||
**kein** `10.0.0.0/8` (nur `192.168/16` + CGNAT-minus-Mesh) → `.36/.37` sind über WARP routbar.
|
||||
- ⏳ **User-Verify:** WARP am Gerät **neu verbinden** (Profil-Cache), dann `dig vw.emsenhuber.net → .40`
|
||||
und `/admin` über WARP erreichbar.
|
||||
|
||||
### T2 — 404 statt 403 ✅ DURCH (2026-09-01)
|
||||
- Caddyfile `vw`-Block: `@cf_admin {header CF-Connecting-IP *; path /admin /admin/*} → respond 404`.
|
||||
Deploy LXC130 (Backup `/etc/caddy/Caddyfile.bak-tp41-20260901`), reload ok.
|
||||
- WAF-Regel **`f26744eb` gelöscht** (nur noch die gitea-skip-Regel `3c707c3c` im Ruleset).
|
||||
- Verify: **Edge `/admin` = 404** (war 403), Edge `/` = 200, **lokal/WARP `/admin` = 200**. ✅
|
||||
|
||||
### Noch offen
|
||||
- **d47435-Revoke** (User, Account API Tokens Write). **T3-Client-Verify** (User, WARP neu verbinden).
|
||||
- **T5** (GitHub/Google-Callbacks — der eigentliche OTP-Fix, User) — **Schritt-für-Schritt:**
|
||||
[`docs/tp41-t5-idp-callback-anleitung.md`](tp41-t5-idp-callback-anleitung.md). **T6/T7/dw-Geli**.
|
||||
- 🔴 **`TERPENE_ANDROID_KEYSTORE_PW`-Rotation erwägen** (Transkript-Leak, s.o.).
|
||||
40
docs/handoff-20260901-tp42-naming.md
Normal file
40
docs/handoff-20260901-tp42-naming.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Handoff 2026-09-01 — TP42 Namens-Vereinheitlichung bf.lan → emsenhuber.net
|
||||
|
||||
> **Angelegt aus einem TP41-Randbefund.** Reine Anlage + Bestandsaufnahme; **keine Live-Änderung**
|
||||
> in dieser Session. Umsetzung = eigene Session.
|
||||
|
||||
## Auslöser
|
||||
Beim Verifizieren des T3-Resolvers (TP41) live gemessen:
|
||||
|
||||
| Resolver | vw.emsenhuber.net | Bewertung |
|
||||
|---|---|---|
|
||||
| 10.40.20.36 / .37 | 10.40.20.40 | ✅ korrekt (reale Client-Resolver, via DHCP) |
|
||||
| 10.40.20.1 (Core) | 188.114.96.10 / .97.10 | public CF (Core macht DoH→CF) |
|
||||
| 10.40.20.16 | CNAME nginx-bf.emsenhuber.net (kein A) | 🔴 stale |
|
||||
| 10.40.20.17 | nginx.bf.emsenhuber.net + 10.40.41.123 | 🔴 stale, totes VLAN1 |
|
||||
|
||||
Daneben: Core `/ip dns static` = 11× `*.bf.lan`; Caddyfile doppelt jeden internen Namen als
|
||||
`*.bf.emsenhuber.net`.
|
||||
|
||||
## Befund-Fundstellen (Start für die Umsetzung)
|
||||
- **Core (`crs326-core`) `/ip dns static`:** router.lan, core.bf.lan, macmini.bf.lan, pve.bf.lan,
|
||||
pve-mcp.bf.lan, nas.bf.lan, docker.bf.lan, platform-pg.bf.lan, ap1.bf.lan, ap2.bf.lan, branch.bf.lan.
|
||||
- **Caddyfile (`caddy/Caddyfile`, LXC130/.40):** `*.bf.emsenhuber.net`-Aliase an nautobot/ccu/iobroker/
|
||||
z2m25/pve-mcp/ha-mcp/n8n-mcp/gitea-mcp/pve/portainer/pbs.
|
||||
- **AdGuard `.36`/`.37`:** aktive Split-Horizon-Rewrites `*.emsenhuber.net → .40` (Sollquelle).
|
||||
- **Stale `.16`/`.17`:** alte AdGuard, `nginx*`-Antworten + `10.40.41.123` → abbauen/klären.
|
||||
- **DHCP:** Search-/Domain-Option je Netz prüfen (welcher Suffix wird verteilt?).
|
||||
|
||||
## Ziel
|
||||
Ein interner Namensraum `emsenhuber.net` (Split-Horizon `.36/.37 → .40`). `.bf.lan` +
|
||||
`.bf.emsenhuber.net` raus. Sollzustand in Nautobot (TP37).
|
||||
|
||||
## Offen / Entscheidungen für die Umsetzungssession
|
||||
1. Zielschema fix: nur `emsenhuber.net`, oder `bf.emsenhuber.net` als **einzige** interne Zone?
|
||||
2. Migrationsreihenfolge ohne DNS-Loch (erst neue Namen, dann alte weg).
|
||||
3. `.16/.17`: laufen die noch, gehören sie abgebaut? (mit TP für AdGuard-Konsolidierung abgleichen)
|
||||
4. Nautobot-Erfassung: Custom Field / Records — abhängig von TP37-Datenmodell.
|
||||
|
||||
## Nicht anfassen
|
||||
Öffentliche Zone `emsenhuber.net` (CF); Resolver-Zuordnung `.36/.37`; `.1`-DNS-Reste auf Clients
|
||||
(User: „bis jetzt kein Problem"). Test-Vantage-Lehre aus TP41 beachten (von zuhause umgeht man CF).
|
||||
72
docs/handoff-20260902-cf-estate-nautobot-ssot.md
Normal file
72
docs/handoff-20260902-cf-estate-nautobot-ssot.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Handoff 2026-09-02 — CF-Estate als SSoT in Nautobot (TP44, Etappe 1)
|
||||
|
||||
> Scope: die Cloudflare-Infrastruktur (Tunnel + App-Ebene) als strukturierte, abfragbare SSoT in
|
||||
> Nautobot abbilden. Etappe 1 = **manuelle Erstbefüllung** über die nativen `nautobot.cloud`-Modelle.
|
||||
> Ausgelöst aus der DB-Pfad-Session (siehe `cf-tunnel-mapping.md` §17).
|
||||
|
||||
## Entscheidung (User, 2026-09-02)
|
||||
|
||||
- **SSoT-Modus:** Etappen — *manuell jetzt, Sync später*. `cf-tunnel-mapping.md` wird zum Snapshot/Zeiger.
|
||||
- **Scope Etappe 1:** *volle CF-Estate* (Tunnel + WARP-Connector + VPC-Service + Hyperdrive + Workers +
|
||||
alle Access-Apps).
|
||||
- **Grundsatz:** Nautobot kann CF **nicht steuern** → „SSoT" = **Dokumentations**-SSoT. CF bleibt
|
||||
operativer Master.
|
||||
|
||||
## Warum ein eigenes TP (TP44), nicht TP36
|
||||
|
||||
TP36 ist in `teilprojekte.md` eng auf *`teilprojekte.md`-Live-Daten + Datei-Aufteilung* geschnitten.
|
||||
Dieselbe Idee (Nautobot als Doku-SSoT), aber andere Dimension → **TP44** (nächste freie Nummer nach TP43).
|
||||
Quick-Index-Zeile + TP-Abschnitt in `teilprojekte.md` sind **noch offen** (die Datei trug bei dieser
|
||||
Session fremde, ungestagte Änderungen — bewusst nicht mit angefasst, um den Commit sauber zu halten).
|
||||
|
||||
## Modell (Nautobot 3.1.7, App `nautobot.cloud`)
|
||||
|
||||
```
|
||||
Manufacturer "Cloudflare"
|
||||
└─ CloudAccount "Cloudflare" (account_number = 393c051f3accf51881d6c98fc5b66c36)
|
||||
├─ CloudResourceType ×6
|
||||
│ cloudflared Tunnel · WARP Connector → cloud.cloudnetwork
|
||||
│ VPC Service · Hyperdrive · Worker · Access Application → cloud.cloudservice
|
||||
├─ CloudNetwork ×4 bf-public · fm.emsenhuber.net · terpene-db · bf-core-mesh
|
||||
└─ CloudService ×14 VPC terpene-db · Hyperdrive terpene(ro)+terpene-rw ·
|
||||
Worker terpene+blaueblueten-n8n · 9× Access-App
|
||||
```
|
||||
|
||||
- **IDs/Ports/Hostnames/Origins** liegen je Objekt in `extra_config` (JSON).
|
||||
- **Service↔Tunnel-Verknüpfung** über das Through-Modell `cloud-service-network-assignments` (3 Rows):
|
||||
`terpene-db↔terpene-db`, `*.emsenhuber.net↔bf-public`, `hass, vw, gitea↔bf-public`.
|
||||
- **Prefix-Routen** (`10.40.0.0/16` bf-core-mesh, `10.101.0.0/24` fm) sind **nicht** als
|
||||
`cloud-network-prefix-assignments` gesetzt, weil die Prefixe nicht in IPAM existieren → in
|
||||
`extra_config.route` belassen (best-effort im Seeder, greift automatisch, sobald die Prefixe in IPAM sind).
|
||||
|
||||
## Werkzeug
|
||||
|
||||
`nautobot/tp44-cf-estate-seed.py` — **idempotenter** Seeder (get-or-create), Datenstand als Inline-Struktur.
|
||||
Token aus `docs/nas-vlan20/stacks/210-nautobot.yml` (gitignored). Aufruf: Dry-Run default,
|
||||
`--commit` schreibt. Re-Run = 26/26 „existiert".
|
||||
*(Datei am 2026-09-06 von `tp36-…` auf `tp44-cf-estate-seed.py` umbenannt — Präfix jetzt korrekt.)*
|
||||
|
||||
## Gotchas (für Etappe 2 / Folgesessions)
|
||||
|
||||
- 🔴 **`CloudService.cloud_networks` ist im Serializer `read_only` und bleibt bei GET leer** — die
|
||||
Verknüpfung wird **ausschließlich** über `cloud-service-network-assignments` geschrieben UND gelesen.
|
||||
Nicht am leeren Convenience-Feld verzweifeln; die Through-Rows sind die Wahrheit.
|
||||
- VPC-Service-API liegt unter `connectivity/directory/services` (Update = **PUT**, voller Body), nicht `/vpc/`.
|
||||
- Der Repo-`CF_API_TOKEN` darf `cfd_tunnel`, aber **nicht** Workers-VPC (`connectivity/directory`) — dort
|
||||
über den `cloudflare`-MCP-Credential gehen.
|
||||
> ⚠️ **ÜBERHOLT (2026-09-11):** falsch. Live getestet liest der `CF_API_TOKEN` aus
|
||||
> `~/.secrets/credentials.env` Hyperdrive/VPC/Workers (alle 200) — der schmale ist `CF_DNS_API_TOKEN`.
|
||||
> Der Teil-B-Sync deckt damit 14/14 ab. Details: `handoff-20260910-tp44-teilb-sync-live.md`.
|
||||
|
||||
## Offen (Etappe 2, eigene Session)
|
||||
|
||||
1. **CF-API→Nautobot-Sync** (Python/n8n): Inline-Daten im Seeder durch Live-Pull ersetzen, periodisch
|
||||
(analog golden-config-bot). Dann ist Nautobot driftfrei.
|
||||
2. ✅ **TP44 in `teilprojekte.md`** eingetragen (Quick-Index + Abschnitt + Ist-Stand) — 2026-09-06.
|
||||
3. IPAM-Prefixe `10.40.0.0/16` + `10.101.0.0/24` anlegen → dann greifen die Prefix-Assignments automatisch.
|
||||
4. ✅ Seeder-Datei nach `tp44-cf-estate-seed.py` umbenannt — 2026-09-06.
|
||||
|
||||
## Verifikation (2026-09-02)
|
||||
|
||||
Counts: CloudAccount 1 · ResourceType 6 · CloudNetwork 4 · CloudService 14 · Service-Network-Assignments 3.
|
||||
Idempotenz-Gegenprobe grün.
|
||||
57
docs/handoff-20260902-tp25-fund-e-messung.md
Normal file
57
docs/handoff-20260902-tp25-fund-e-messung.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Handoff 2026-09-02 — TP25 Fund E: die Abschlussmessung, und was sie entschieden hat
|
||||
|
||||
**Kurz:** Die für heute früh vorgemerkte Messung ist gelaufen. **7.24.1 hat den
|
||||
`reauthenticating`-Sturm aufgelöst, nicht `ft-over-ds`.** Hebel 1 war widerlegt und ist zu Recht
|
||||
zurückgebaut; Hebel 2–4 entfallen. **Fund E ist geschlossen** — ohne Geräte-Write.
|
||||
|
||||
## Was Fund E war
|
||||
|
||||
Ein `reauthenticating`-Sturm, sauber isoliert auf **einen** Client (iPhone
|
||||
`F2:62:4C:E1:AF:09`) und **eine** SSID (`dirtyvader-main`, die einzige mit
|
||||
`ft=yes ft-over-ds=yes`). Baseline: 93/93 auf genau diesem Client und dieser SSID. Hebel 1
|
||||
(`ft-over-ds=no`) lief am 31.08. **6,4 h allein** und machte es **schlimmer** (124 ≈ 19/h + 2
|
||||
erlebte Ausfälle) → am 01.09. zurückgebaut, Transaktion `TP25-fund-e-ft-over-ds` geschlossen.
|
||||
Der Einbruch auf ~0/h fiel exakt auf das **TP27-Upgrade 7.24.1** (Core-Reboot 31.08. 14:36).
|
||||
|
||||
## Vorbedingung zuerst (CLAUDE.md-Gotcha: „grep caps + uptime vor Client-Diagnose")
|
||||
|
||||
- Core-Uptime **1d18h** → letzter Reboot 31.08. 14:36; **kein** Reboot am 01./02.09.
|
||||
- `caps joined = 0` an beiden Tagen.
|
||||
- ⇒ Die Zahlen unten sind echte Client-Ereignisse, keine Reboot-Artefakte.
|
||||
|
||||
## Messung (Kollektor `/opt/tp5-syslog/log/10.40.20.1/`, via pve→`pct exec 400`)
|
||||
|
||||
| Tag | reauth total | davon iPhone F2:62 | distinct MACs | data loss / deauth | Kontext |
|
||||
|---|---|---|---|---|---|
|
||||
| 08-31 | 225 | 218 | 6 | (Upgrade+Hebel1) | Hebel-1-Fenster + 2 Upgrade-Reboots |
|
||||
| 09-01 | 44 | 40 | 4 | 0 | 7.24.1, Hebel 1 mittags zurückgebaut |
|
||||
| **09-02** (00:00–08:37) | **4** | **4** | **1** | **0** | 7.24.1 + `ft-over-ds=yes`, sauberes Fenster |
|
||||
|
||||
- **218 → 40 → 4.** Am 09-02 vier isolierte Einzelereignisse (01:13, 02:00, 03:14, 08:01),
|
||||
**kein Burst**, alle `dirtyvader-main` (Interface `cap-wifi3`/`cap-wifi6` — die `cap-wifiN`-Karte
|
||||
wandert, deshalb NICHT einem AP zugeschrieben). ≈ **0,46/h** gegen Baseline 93 bzw. Hebel-1 **19/h**.
|
||||
- Der iPhone ist **präsent und stabil** — er verbindet und erzeugt die 4 Zeilen, ist also nicht
|
||||
„still, weil abwesend".
|
||||
- Die 97 `association rejected` am 09-01 fallen auf den **Rollback-/Re-Provisioning-Vorgang**
|
||||
(viele MACs = Infrastruktur, per Gotcha), nicht auf einen Client; am 09-02 nur 5.
|
||||
|
||||
## Schluss & Entscheidung
|
||||
|
||||
**7.24.1 war die Ursache/der Fix, nicht `ft-over-ds`.** Der Restwert (~0,5/h isolierte
|
||||
Einzel-Reauth eines iPhones, 0 Ausfälle) ist normales iOS-Roaming, kein Defekt.
|
||||
**Hebel 2–4 (`ft=no`, `2g-probe-delay`, `signal-range`) werden NICHT gezogen. Fund E geschlossen.**
|
||||
|
||||
Kein Geräte-Write: Sollzustand steht bereits (`sec-main` = `ft=yes ft-over-ds=yes`, Flotte 7.24.1,
|
||||
Transaktion `zurueckgebaut`, Compliance **140/140**).
|
||||
|
||||
## Bleibt offen (nicht Fund E)
|
||||
|
||||
- **ap2 unterperformt** (2 m / −80 dBm, 23:02-Befund) — eigener In-situ-Unterpunkt in TP25,
|
||||
kein FT-/Auth-Thema. TP25 bleibt deshalb als Sammel-TP offen.
|
||||
|
||||
## Merkregel bestätigt
|
||||
|
||||
Der Fall ist ein Lehrstück für zwei CLAUDE.md-Regeln: (a) **Reboots zuerst ausschließen** hätte am
|
||||
31.08. verhindert, den Upgrade-Reboot-Burst für Client-Instabilität zu halten; (b) **eine Drift/ein
|
||||
Symptom im offenen Versuch sieht aus wie ein Defekt** — Hebel 1 „verbesserte auf 0/h" war in
|
||||
Wahrheit das parallele Upgrade. Die einzelne Messung nach dem Rückbau hat beides getrennt.
|
||||
113
docs/handoff-20260903-tp25-tp28-kanalplan-messung.md
Normal file
113
docs/handoff-20260903-tp25-tp28-kanalplan-messung.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# Handoff 2026-09-03 — TP25/TP28: Kanalplan live, In-situ-Messung offen
|
||||
|
||||
**Kurz:** ap1 haengt jetzt am Sideboard (Trunk auf `ether3`), der TP25-Kanalplan ist am
|
||||
Manager gesetzt (**ap1 5260/5280 + ch1**, **ap2 5300/5320 + ch11**, **ap3 5180 + ch6**),
|
||||
und alle drei APs funken. 35 Clients an der Registration-Table (vorher 30, +5 auf ap1).
|
||||
**Was fehlt: die In-situ-Messung** — Aufstellorte begehen und entscheiden, ob der Zustand
|
||||
Zielzustand wird (dann Template + Commit der Akte) oder ob nachjustiert werden muss.
|
||||
|
||||
## Was am 03.09. live gesetzt wurde
|
||||
|
||||
L2 auf `crs326-core`:
|
||||
- `ether3` als AP-Trunk fuer ap1 (analog `ether15`/`ether21`) — Template gepflegt
|
||||
- Akte `TEST-ether3-trunk-ap1-sideboard-2` (Scope `bridge-vlan`, `state=committed`,
|
||||
expires 2026-09-10)
|
||||
|
||||
WLAN am Manager (`crs326-core`):
|
||||
- `ch-5g-ap1`: 5180 → **Frequenz-Liste 5260,5280** (DFS Band B, ch52/56)
|
||||
- `ch-5g-ap2`: 5220 → **Frequenz-Liste 5300,5320** (DFS Band B, ch60/64)
|
||||
- Zwei Provisioning-Regeln fuer ap1 neu (radio-mac `E5`=5G, `E6`=2G) — analog ap2/ap3
|
||||
- `remote-cap provision` auf ap1 und ap2 gefahren
|
||||
- Akte `TP25-kanalplan-ap1-live` (Scope `wifi-channel`, `state=open`, expires 2026-09-10)
|
||||
|
||||
Live-Verifikation:
|
||||
- ap1: 9/9 Interfaces `running=true` am CAP (Manager-Anzeige `running=false` ist der bekannte
|
||||
Post-Reprovisioning-Gotcha, s. CLAUDE.md — Wahrheit am CAP)
|
||||
- ap2: 9/9 Interfaces `running=true`
|
||||
- ap3: unveraendert
|
||||
- 35 Clients (vor Aenderung 30)
|
||||
|
||||
## Was fuer die naechste Session zu tun ist
|
||||
|
||||
**Fokus = messen, nicht nachjustieren, bis die Aufstellorte belegt sind.**
|
||||
|
||||
Zwei offene Frage aus TP25/TP28, die vor Ort beantwortet werden muessen:
|
||||
|
||||
1. **Aufstellort ap1 (Sideboard)** — Abdeckung akzeptabel? Vorher stand ap1 im Technik UG, jetzt
|
||||
am Sideboard (Test). Signal in den Ecken (Terrasse, Bad, hintere Zimmer) messen.
|
||||
2. **ap2 unterperformt** (TP25 Rest-Punkt, In-situ 2 m/−80 dBm am 08-31). Vermutung: RF/Antenne/HW,
|
||||
moeglicherweise auch nur `ch149`-Leistungsproblem (jetzt weg, 5300 statt 5220). Die
|
||||
Kanalaenderung koennte das Symptom bereits behoben haben — deshalb **zuerst neu messen**,
|
||||
bevor man an Antennen oder Hardware denkt.
|
||||
|
||||
## Aufstellorts-Messplan (Vorschlag, bewusst knapp)
|
||||
|
||||
Pro Standort (Wohnzimmer, Kueche, Bad, Terrasse, Schlafzimmer, Technik UG):
|
||||
- Signal in dBm auf `dirtyvader-main` (5 GHz) mit App am Handy
|
||||
- Welcher AP wird ausgewaehlt (BSSID am APx-Radio abgleichen — s. Manager-Registration-Table)
|
||||
- Kurz eine Datei ziehen (SpeedTest oder `iperf3` gegen `10.40.20.10`), damit reale Throughput-
|
||||
Zahl da ist, nicht nur RSSI
|
||||
- 2,4 GHz nur pruefen, wenn das 5-GHz-Signal an dem Standort schlecht ist (< −75 dBm)
|
||||
|
||||
Am Manager parallel:
|
||||
- `/interface wifi registration-table print terse where ssid=dirtyvader-main` — Signal/Rate live
|
||||
- `/interface wifi radio print` gibt aktuelle Frequenz je Radio (5260 vs 5280, 5300 vs 5320 —
|
||||
DFS hat einen der beiden gewaehlt)
|
||||
|
||||
## Gotchas fuer die Messsession (aus CLAUDE.md)
|
||||
|
||||
- **`/interface wifi scan` NUR am Manager**, nicht am CAP (`not allowed`).
|
||||
- **Registration-Table NUR am Manager** — am CAP leer.
|
||||
- **`cap-wifiN`-Karte wandert bei jedem Rejoin.** Vor der Auswertung eines Ereignisses
|
||||
`/interface wifi radio print terse proplist=cap,radio-mac,interface` am Manager lesen; wenn
|
||||
zwischen Ereignis und Auswertung ein Rejoin liegt, Zuordnung als **unbekannt** behandeln.
|
||||
- **`list_wifi_interfaces` leakt PSKs** — nicht benutzen; stattdessen
|
||||
`/interface wifi radio print` bzw. `/interface wifi print terse where master=yes proplist=...`.
|
||||
- **Ein `caps,info`-Burst ist Infrastruktur, ein Client-MAC-Burst ist ein Client** — vor jeder
|
||||
Client-Diagnose `/system resource get uptime` am Core lesen und `grep " caps,"` im TP5-Log.
|
||||
- **DFS-CAC** dauert beim ersten Einschalten eines DFS-Kanals ~60 s. Bei einem Radar-Event
|
||||
wechselt der Kanal automatisch auf den Zweitwert (5260↔5280 bzw. 5300↔5320) — deshalb steht
|
||||
im Channel-Objekt eine **Liste**, kein Einzelwert.
|
||||
|
||||
## Rollback (falls die Messung schlecht ausfaellt)
|
||||
|
||||
Der Snapshot `docs/transaktionen/TP25-kanalplan-ap1-live.snapshot.rsc` haelt den Vorher-Zustand
|
||||
(ap1=5180, ap2=5220, keine ap1-Provisioning-Regeln). Rollback per:
|
||||
|
||||
```
|
||||
python3 nautobot/gc-transaktion.py rollback --change-id TP25-kanalplan-ap1-live
|
||||
```
|
||||
|
||||
Der Trunk auf `ether3` (physischer Umbau) muss separat via
|
||||
`TEST-ether3-trunk-ap1-sideboard-2` behandelt werden.
|
||||
|
||||
## Commit-Weg (falls die Messung gut ausfaellt)
|
||||
|
||||
Zwei Sachen ins Template `nautobot/mikrotik_routeros.j2`:
|
||||
1. Zeilen 206–207: `frequency=5180`/`5220` → Frequenz-Listen `5260,5280`/`5300,5320`
|
||||
2. Nach den bestehenden Provisioning-Zeilen fuer ap2/ap3 die zwei ap1-Regeln einfuegen
|
||||
(radio-mac `D0:EA:11:4D:40:E5` = 5G, `D0:EA:11:4D:40:E6` = 2G) — Slave-Set analog ap2/ap3
|
||||
|
||||
Danach:
|
||||
```
|
||||
python3 nautobot/gc-transaktion.py commit --change-id TP25-kanalplan-ap1-live
|
||||
```
|
||||
|
||||
Skript verweigert den Commit, solange die SoT nicht nachgezogen ist — der Ablauf funktioniert
|
||||
nur in dieser Reihenfolge.
|
||||
|
||||
## Ein-Scope-Grenze der Akte (wichtig, wenn Compliance-Status gelesen wird)
|
||||
|
||||
Die Akte deckt formell **nur `wifi-channel`**. Die zwei ap1-Provisioning-Adds fallen unter
|
||||
`wifi-provisioning` — das begin-Skript erlaubt aber **nur eine offene Akte je Geraet** (Regel 3).
|
||||
Deshalb steht im `commands.rsc` der Akte ein Header, der beides zusammenfuehrt. Im naechsten
|
||||
Compliance-Run wird `wifi-provisioning` als „fremd" (nicht durch die aktive Akte gedeckt)
|
||||
gemeldet werden — das ist **erklaerbarer, nicht undokumentierter Drift**. Beim Commit gehoert
|
||||
BEIDES ins Template.
|
||||
|
||||
## Aufraeumkandidat, wenn alles glatt geht
|
||||
|
||||
- TP25-Ist-Stand-Block: Punkt „ap2 unterperformt" als geloest markieren (falls Messung das
|
||||
bestaetigt).
|
||||
- TP28-Ist-Stand-Block: „ap1 funkstill" ausbauen — ist mit 09-03 erledigt.
|
||||
- Quick-Index-Zeile TP25 kann bei erfolgreichem Commit auf `✅` gesetzt werden.
|
||||
70
docs/handoff-20260904-tp25-konsole-n-clients.md
Normal file
70
docs/handoff-20260904-tp25-konsole-n-clients.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Handoff 2026-09-04 — TP25: Klick-Konsole auf N Clients + Pin-UI
|
||||
|
||||
**Kurz:** Die Klick-Konsole (`docs/tp6-marker/server.py`, Port 3031) war beim Multi-Pin-Umbau
|
||||
(2026-09-04, `tp25-pin-multi.sh` + `TP25_PHONES`) **nicht** mitgezogen worden — sie zeigte weiter
|
||||
hartkodiert zwei Clients (iPhone/S22) und pinnte ueber die alte Gegen-AP-Automatik. Jetzt ist sie
|
||||
auf **N Clients** generalisiert und hat eine **Pin-UI**: Signal/AP/Ping-Verlust je Client live,
|
||||
Pinnen band-genau direkt in der Konsole. Die alte 2-Client-Automatik ist entfernt.
|
||||
|
||||
## Was umgebaut wurde
|
||||
|
||||
`docs/tp6-marker/server.py` (Hauptumbau):
|
||||
- **Client-Liste aus Datei statt hartkodiert:** `geraete()` liest `geraete.txt` aus dem
|
||||
Laufverzeichnis (schreibt `tp25-walk-messung.sh`, eine Zeile `name|ip|mac` je Client). Fallback
|
||||
auf die zwei alten MACs fuer Alt-Laeufe.
|
||||
- **Kein eigenes SSH mehr in der Konsole:** der `beobachter()`-Thread (2 MACs per SSH,
|
||||
`beide-telefone.csv`) ist raus. Stattdessen liest die Konsole je Client die **letzte Zeile** von
|
||||
`sampler-<name>.csv` (`sta_iface`, `sta_signal`) und den **juengsten Ping-Verlust** aus
|
||||
`walk-ping-<name>.csv` (leeres `ms` = Verlust). Eine SSH-Session weniger gegen den Core-SPOF.
|
||||
- **N Client-Karten** statt der festen iPhone/S22-Zeile: Name, AP (via `ap_map()`), Signal dBm,
|
||||
Ping-Verlust der letzten ~30 s. **Alarm**, wenn ein **gepinnter** Client `sta_iface == "absent"`
|
||||
ist → „<name> HAENGT NIRGENDS — nicht weitergehen" (Nachfolger des alten S22-Alarms).
|
||||
- **Pin-UI** (Karte „Pinnen (Multi-Pin)"): je Client ein `<select>` mit `frei` / `apX/5GHz` /
|
||||
`apX/2,4GHz` (Ziele aus `ap_map()` abgeleitet) plus drei Aktionen:
|
||||
- **„Pin setzen"** → baut `TP25_PINSPEC="name|mac|ap|band;…"` aus den Nicht-`frei`-Auswahlen und
|
||||
ruft `bash docs/tp25-pin-multi.sh set` im Thread.
|
||||
- **„Pin loesen"** → `bash docs/tp25-pin-multi.sh off`.
|
||||
- **„verify"** → `bash docs/tp25-pin-multi.sh verify`, Ausgabe als Statuszeile.
|
||||
Neuer Endpunkt `POST /pinmulti` (analog zum alten `/pin`).
|
||||
- **Entfernt:** `IPHONE_MAC`/`S22_MAC`, `_live`/`_auto`, `entscheide()`, `pin_lesen()`/
|
||||
`pin_setzen()` (via `tp25-pin-s22.sh`), die ap1/ap2/auto-Buttons und der `PIN_SH`-Aufruf.
|
||||
`tp25-pin-s22.sh` bleibt als Skript erhalten (liefert `map`), wird aber von der Konsole nicht
|
||||
mehr zum Pinnen aufgerufen.
|
||||
|
||||
`docs/tp25-runde.sh`:
|
||||
- `aufraeumen()` loest jetzt `tp25-pin-multi.sh off` statt `tp25-pin-s22.sh off` (Kommentar
|
||||
angepasst: die Konsole pinnt nicht mehr automatisch).
|
||||
|
||||
## Bedienung (Messablauf)
|
||||
|
||||
```
|
||||
bash docs/tp25-runde.sh [name] # Konsole (3031) + Messung, Adresse fuer das Telefon
|
||||
```
|
||||
|
||||
1. Am Telefon die Konsole oeffnen, einmal irgendwo tippen (schaltet den Signalton frei).
|
||||
2. In der Konsole **pinnen**: je Client AP/Band waehlen, „Pin setzen". Clients ohne Ziel bleiben
|
||||
frei (das Skript raeumt vorher alle `TP25-PINM-*`-Regeln ab).
|
||||
3. Losgehen. 🚶 beim Losgehen, 📍 beim Stehenbleiben, Raum antippen. Alarm = ein gepinnter Client
|
||||
haengt nirgends.
|
||||
4. „⏹ Aufzeichnung stoppen" (oder Ctrl-C im Terminal). Der Wrapper loest den Multi-Pin beim Beenden.
|
||||
|
||||
Auswertung: `python3 docs/tp25-gehweg-auswertung.py --dir docs/messdaten/tp25-runde-<name>`
|
||||
|
||||
## Was noch offen ist (braucht die Geraete vor Ort)
|
||||
|
||||
- **Live-Test mit N Geraeten im Netz** (Plan-Verifikation Schritt 3): `TP25_PHONES="…" bash
|
||||
docs/tp25-runde.sh test` → N Karten sichtbar, pinnen → `bash docs/tp25-pin-multi.sh verify` zeigt
|
||||
die Regeln, gehen/Raeume/stoppen → Auswertung liefert die Raumtabelle mit N Geraeten.
|
||||
- **Aufraeumen** (Schritt 4): nach dem Lauf `bash docs/tp25-pin-multi.sh off` — keine
|
||||
`TP25-PINM-*`-Regeln am Manager zurueck.
|
||||
|
||||
Statisch verifiziert (ohne Geraete): AST-Parse ok, keine stale Referenzen auf die alte Automatik,
|
||||
Smoke-Render mit 2 Test-Clients ok, `bash -n` auf allen drei Shell-Skripten ok.
|
||||
|
||||
## Gotchas (unveraendert, aus CLAUDE.md)
|
||||
|
||||
- **`cap-wifiN`-Karte wandert bei jedem Rejoin** — `tp25-walk-messung.sh` friert sie als
|
||||
`ap-map.txt` im Messlauf ein; die Konsole beschriftet daraus.
|
||||
- **Registration-Table nur am Manager** — die Sampler (`tp6-monitor-core.sh`) fragen den Core ab,
|
||||
nicht die CAPs.
|
||||
- **`sshpass -e`, nie `-p`** — gilt weiter fuer alle Skripte, die den Core ansprechen.
|
||||
127
docs/handoff-20260906-tp37-34-36-plan.md
Normal file
127
docs/handoff-20260906-tp37-34-36-plan.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Handoff 2026-09-06 — Plan TP37 (P1+2) → TP34, TP36 parallel
|
||||
|
||||
> **Sessiontyp:** „erst planen, nichts bauen" (User-Entscheid 2026-09-06). **Kein Nautobot-Write.**
|
||||
> Dieses Dokument ist der verzahnte Runbook für die drei nachfolgenden Build-Sessions.
|
||||
> Datenmodell-Entscheid: **native Nautobot-Modelle, keine eigene App** (konsistent zu TP44).
|
||||
|
||||
## 1. Ausgangslage — live gegen die API gelesen (2026-09-06)
|
||||
|
||||
| | Wert | Bedeutung |
|
||||
|---|---|---|
|
||||
| Nautobot | `http://10.40.20.30:8080`, v3.1.7 | Apps: **Golden Config 3.0.7 + Nornir** (cloud-Modelle sind Core) |
|
||||
| Devices | 9 | 4 aktive MikroTik + decommissioned/Rest — in Build-Schritt 0 verifizieren |
|
||||
| **VirtualMachines** | **0** | TP37 P1 offen |
|
||||
| **Clusters** | **0** | TP37 P1 offen |
|
||||
| **ipam.Service** | **0** | TP37 P2 offen |
|
||||
| **CustomFields** | **0** | TP36 offen |
|
||||
| Relationships / Tags | 0 / 0 | — |
|
||||
| `cloud.*` (Account/ResType/Network/Service) | 1 / 6 / 4 / 14 | ✅ **TP44 Etappe 1** — CF-Estate steht |
|
||||
|
||||
**Kernbefund:** TP37 **Punkt 3 (CF-Connectoren) ist durch TP44 erledigt** (native cloud-Modelle). Echt
|
||||
offen bleibt das **Substrat** (P1) und die **Dienste** (P2) — und genau darauf sitzt TP34.
|
||||
|
||||
## 2. Entscheidungen (User, 2026-09-06)
|
||||
|
||||
1. **Erst planen, nichts bauen** — diese Session schreibt nichts nach Nautobot.
|
||||
2. **Native Modelle** — `virtualization.Cluster/VirtualMachine` + `ipam.Service`, **keine eigene App**.
|
||||
3. **TP44-Doku aufgeräumt** — Quick-Index-Zeile + Abschnitt in `teilprojekte.md`, Seeder
|
||||
`nautobot/tp36-…` → `tp44-cf-estate-seed.py` umbenannt.
|
||||
|
||||
## 3. Reihenfolge / Abhängigkeit (korrigiert)
|
||||
|
||||
```
|
||||
TP37 P3 (CF-Connectoren) ─── ✅ ERLEDIGT via TP44 ───┐
|
||||
│ gleiche native-Modell-Linie
|
||||
TP37 P1 (Hosts/Container → VirtualMachine) │
|
||||
└─► TP37 P2 (Dienste → ipam.Service) ─► TP34 (Caddyfile via GC)
|
||||
|
||||
TP36 (CustomFields auf den 4 Devices + Datei-Split) ── ∥ unabhängig, jederzeit parallel
|
||||
```
|
||||
|
||||
**Grund für die Unabhängigkeit von TP36:** seine Live-Daten-CustomFields hängen an den **bestehenden
|
||||
`dcim.Device`**, nicht an neuen VM/Service-Objekten. TP34 dagegen kann ohne die Backend-`ipam.Service`
|
||||
aus P2 nichts rendern → **TP37 vor TP34** bleibt zwingend.
|
||||
|
||||
---
|
||||
|
||||
## 4. TP37 Punkt 1 — Substrat: Hosts + Container als VMs
|
||||
|
||||
**Modell-Mapping (nativ):**
|
||||
- `virtualization.ClusterType`: `Proxmox VE`, `Synology Docker`, `Docker Desktop`.
|
||||
- `virtualization.Cluster`: `pve`, `nas-bf`, `macmini` (je einer, passender ClusterType).
|
||||
*(Die physischen Hosts als eigene `dcim.Device` sind **optional** und kommen frühestens in einer
|
||||
Etappe 2 — für den Doku-SSoT reicht der Cluster als Gruppierung. Empfehlung: Etappe 1 ohne Host-Devices.)*
|
||||
- `virtualization.VirtualMachine` je Workload, mit `cluster` + `primary_ip4`:
|
||||
- **pve:** alle LXCs (u.a. `platform-pg` 105/`.20.20`, Docker-LXC 400/`.20.126`, `mcast-relay` 108,
|
||||
influxdb, MariaDB 302/`.20.23`, …).
|
||||
- **nas-bf (DS923, Portainer ep14):** Nautobot-Stack-Container, ggf. Caddy/weitere.
|
||||
- **macmini (Docker Desktop):** `n8n`/`n8n-redis`/`n8n-mcp`/`gitea-mcp` + terpene-Worker `:8890`.
|
||||
|
||||
**Build-Schritt 0 (read-only Inventur, BEVOR geseedet wird):** je Host die Workloads mit Name, Rolle,
|
||||
primärer IP enumerieren — `pct list` + `pct config <id>` über **pve-mcp**, Portainer-API (ep14) für die
|
||||
NAS, `docker ps` auf dem macmini. Ergebnis in eine **Inline-Datenstruktur** (Muster: `tp44-cf-estate-seed.py`)
|
||||
→ idempotenter Seeder `nautobot/tp37-substrat-seed.py` (get-or-create, Dry-Run default, `--commit`).
|
||||
|
||||
## 5. TP37 Punkt 2 — Dienste als `ipam.Service`
|
||||
|
||||
- Je exponiertem Port ein `ipam.Service`, an die VM (bzw. später das Device) gebunden, das ihn betreibt:
|
||||
Caddy `:80/:443`, AdGuard `:53` (bf1/bf2), Nautobot `:8080`, n8n `:5678`, HA `:8123`, Portainer `:9443`,
|
||||
`pve-mcp :3000`, gitea, Vaultwarden, …
|
||||
- **Quelle ohne Raten:** die Ports stehen in `CLAUDE.md` (Hardware/Tooling) **und** in den
|
||||
`extra_config.origin/port`-Feldern der TP44-`CloudService`-Objekte — gegeneinander abgleichen.
|
||||
- Idempotenter Seeder `nautobot/tp37-dienste-seed.py`.
|
||||
|
||||
## 6. 🔴 Auflage: Compliance-Gegenprobe (aus TP37 selbst)
|
||||
|
||||
Nach P1+2 **muss** `python3 nautobot/gc-transaktion.py status` bzw. `gc-configplan.py --refresh-compliance`
|
||||
zeigen, dass die Geräte-Compliance **unverändert 140/140** ist. VMs/Services hinzuzufügen darf die
|
||||
Golden-Config-Pipeline der 4 MikroTik **nicht** berühren. P1 und P2 sind je ein **abnehmbarer** Schritt
|
||||
mit dieser Gegenprobe danach — nicht als Nebeneffekt von etwas anderem.
|
||||
|
||||
---
|
||||
|
||||
## 7. TP34 — Caddyfile via Golden Config (nach P2)
|
||||
|
||||
- **Vorbedingung:** Backend-Dienste existieren als `ipam.Service` (P2).
|
||||
- **Modell (nativ):** Proxy-Route = **Relationship** (oder CustomField) Frontend `caddy`-Service ↔ Backend-
|
||||
Service, plus den öffentlichen Hostname am Backend. GC-Job + Jinja rendert den Caddyfile, Diff gegen
|
||||
live `caddy-bf1`, neue ComplianceRule `caddyfile`.
|
||||
- **Schritt 0 / Quick-Win (sobald gebaut wird):** `terpene.teilzeitladen.xyz → http://10.40.20.167:8890`
|
||||
als **manueller** Caddy-Block, damit terpene läuft, bevor die GC-Pipeline steht.
|
||||
- ⚠️ **Offener Design-Punkt:** Caddy ist **kein RouterOS-Gerät** — GC an ein Nicht-Netzgerät zu deployen
|
||||
(Caddy-Reload) ist neu (die „nicht in TP37"-Grenze). Deploy-Pfad in der TP34-Build-Session entscheiden.
|
||||
|
||||
## 8. TP36 — Live-Daten-CustomFields + Datei-Split (parallel)
|
||||
|
||||
- **CustomFields auf `dcim.Device`:** `ros_version`, `compliance_pct`, `dhcp_server_count`, `mgmt_ip`,
|
||||
`dns_upstream_mode`. Compliance-Zahl kommt aus **GC selbst**, der Rest aus MikroMCP/REST.
|
||||
- **Skript `nautobot/gc-snapshot.py`** (neu — existiert noch nicht): liest live, setzt die CFs, rendert
|
||||
`docs/teilprojekte-aktuell.md` als **read-only Snapshot**.
|
||||
- **Datei-Split:** `teilprojekte-index.md` (nur aktive TPs, eine Zeile) · `teilprojekte-aktuell.md`
|
||||
(Live-Snapshot) · `teilprojekte-archiv.md` (unverändert). `/projektstatus` liest **Index + Archiv**.
|
||||
- **Unabhängig von TP37** → kann sofort/parallel starten.
|
||||
|
||||
---
|
||||
|
||||
## 9. Empfohlene Reihenfolge der Build-Sessions
|
||||
|
||||
1. **TP37 P1** (Substrat) — Inventur → Seeder → Compliance-Gegenprobe.
|
||||
2. **TP37 P2** (Dienste) — schließt an P1 an, gleiche Gegenprobe.
|
||||
3. **TP34** — nach P2 (Quick-Win terpene als Schritt 0).
|
||||
4. **TP36** — jederzeit parallel zu 1–3.
|
||||
|
||||
## 10. Offene Entscheidungen je Build-Session (nicht heute)
|
||||
|
||||
- **TP34:** Proxy-Route-Modell (Relationship vs. CustomField) + Caddy-Deploy-Pfad (GC an Nicht-Netzgerät).
|
||||
- **TP37:** Hosts als eigene `dcim.Device` anlegen oder nur Cluster? (Empfehlung: Etappe 1 nur Cluster.)
|
||||
- **TP36:** genaues Feld-Set + wie oft `gc-snapshot.py` läuft (Bot analog golden-config vs. on-demand).
|
||||
|
||||
## 11. Was diese Session geändert hat (nur Doku)
|
||||
|
||||
- `nautobot/tp36-cf-estate-seed.py` → **`nautobot/tp44-cf-estate-seed.py`** umbenannt (+ 4 Referenzen,
|
||||
+ Docstring-Titel TP36→TP44).
|
||||
- `teilprojekte.md`: Quick-Index-Zeile TP44; Ist-Stand-Bullet 2026-09-06; TP34/TP36/TP37-Abschnitte auf
|
||||
den korrigierten Stand gezogen; **neuer TP44-Abschnitt** mit Anker.
|
||||
- `handoff-20260902-cf-estate-nautobot-ssot.md` + `cf-tunnel-mapping.md`: Dateiname-Referenzen + erledigte
|
||||
TODOs nachgezogen.
|
||||
- **TP23-Quick-Index-Zeile** (fremde, korrekte Fremd-Änderung ✅→⏳) auf User-Okay mit übernommen.
|
||||
57
docs/handoff-20260910-tp44-teilb-sync-live.md
Normal file
57
docs/handoff-20260910-tp44-teilb-sync-live.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Handoff 2026-09-10 — TP44 Teil B: CF-Estate-Sync als Nautobot-Job LIVE
|
||||
|
||||
> **Ergebnis:** Der Cloudflare-Estate→Nautobot-Sync läuft als **täglicher Nautobot-Job**
|
||||
> (`CFEstateSync`, grouping `TP44 / Cloudflare`). Dry-Run + Commit-Run sauber: **4 CloudNetworks /
|
||||
> 14 CloudServices, alle CF-Endpoints lesbar, 0 Drift.** CF bleibt operativer Master, Nautobot ist
|
||||
> read-only Dokumentations-SSoT. **TP44 ist damit vollständig durch.**
|
||||
|
||||
## Governance (User, 2026-09-09)
|
||||
Periodische externe→Nautobot-Syncs leben als **Nautobot-Jobs** in `bf-infra/jobs/` und werden **in
|
||||
Nautobot geplant** — kein per-Task-Container, kein Cron. Künftige Syncs = weitere Jobs in `jobs/`.
|
||||
|
||||
## Was live ist
|
||||
- **Runtime:** `jobs/cf_estate_sync.py` (`CFEstateSync`, ORM). Pull der CF-API (urllib+Bearer),
|
||||
Upsert per `extra_config`-Match (`tunnel_id`/`script`/`id`/`service_id`), Verwaisung = `stale`-Flag
|
||||
statt Löschen. 403-tolerant (fehlender Scope kippt den Sync nicht; Verwaisung wird dann übersprungen).
|
||||
- **Registrierung:** `jobs/__init__.py` ruft `register_jobs(CFEstateSync)`; **Repo-Wurzel-`__init__.py`**
|
||||
macht `bf_infra` als reguläres Paket sichtbar.
|
||||
- **Token:** Nautobot-Secret `cf-api-token` (Provider `environment-variable`) → `CF_API_TOKEN` am
|
||||
`nautobot-worker`, verdrahtet im Anchor-`environment` von `docs/nas-vlan20/stacks/210-nautobot.yml`
|
||||
(gitignored). Wert = der breite `CF_API_TOKEN` aus `~/.secrets/credentials.env` (liest 14/14).
|
||||
- **Schedule:** `ScheduledJob "CF Estate Sync – taeglich"`, `interval=daily`, `start_time=2026-09-11T03:00:00Z`
|
||||
(= 05:00 Europe/Vienna, vor den Golden-Config-Läufen), `enabled=True`, `dryrun=False`.
|
||||
- **GitRepository:** `bf-infra` (`provided_contents=['extras.job']`) — war schon verdrahtet.
|
||||
|
||||
## Drei load-bearing Funde (sonst lädt/plant der Job nicht)
|
||||
1. **Repo-Wurzel `__init__.py` ist Pflicht.** Nautobot 3.1.7 lädt Git-Repo-Jobs über
|
||||
`import_modules_privately()` → `pkgutil.walk_packages([GIT_ROOT])`. walk_packages entdeckt **nur**
|
||||
reguläre Pakete (mit `__init__.py`), **keine** Namespace-Packages. Ohne die Datei ist der geklonte
|
||||
`GIT_ROOT/bf_infra/` unsichtbar → `jobs/` wird nie importiert. Symptom: Git-Sync **SUCCESS**, aber
|
||||
Log „No jobs were registered on loading the `bf_infra.jobs` submodule" und **kein** Job-DB-Eintrag.
|
||||
bf-infra ist das **erste** Git-Repo mit `extras.job` — daher nie zuvor aufgetreten. Der `module_path`-
|
||||
Filter des Loaders importiert nur `bf_infra` + `bf_infra.jobs.*`; `nautobot/`, `routeros/` etc. bleiben
|
||||
unberührt.
|
||||
2. **`register_jobs()` gehört ins Paket-`__init__`**, nicht nur ins Submodul (Doku bestätigt).
|
||||
3. **`Meta.has_sensitive_variables = False`** nötig — Default `True` ⇒ Nautobot verweigert das Scheduling
|
||||
(„Job may have sensitive input variables"). Der Job nimmt nur `dryrun` (Boolean); das Token kommt aus
|
||||
dem Secret, nicht aus einer Job-Variable.
|
||||
|
||||
## Zwei Daten-/Code-Funde beim Dry-Run
|
||||
- **VPC-Bug:** VPC-Directory-Services tragen ihren Identifier in **`service_id`**, nicht `id`. Der Job las
|
||||
`id` (=None) → per `.get(mk)==None` matchte er ein Fremdobjekt (App Launcher) und ließ den echten
|
||||
`terpene-db` auf stale laufen. Fix: VPC nutzt `service_id`; `_upsert` überspringt `mv=None` generell.
|
||||
- **Seed-Artefakt:** der geseedete CloudService `terpene-db` hatte `extra_config.service_id: null`
|
||||
(der echte `019fa3d5-…` stand beim Seed nur in den Hyperdrive-Einträgen als `vpc_service_id`).
|
||||
**Einmalig reconciled** (PATCH `service_id=019fa3d5-…`) → seither matcht der Sync sauber, 0 Drift.
|
||||
|
||||
## Drift-Korrektur (nicht stillschweigend)
|
||||
Die frühere Notiz „Repo-`CF_API_TOKEN` darf kein Workers-VPC → über den `cloudflare`-MCP-Credential"
|
||||
(TP44-Prosa + `handoff-20260902-…`) war **falsch**. Live getestet liest der `CF_API_TOKEN` aus
|
||||
`~/.secrets/credentials.env` Hyperdrive/VPC/Workers (alle 200). Der schmale Token ist `CF_DNS_API_TOKEN`
|
||||
(403). Der `cloudflare`-MCP ist der **remote OAuth-MCP** (kein API-Token) und für einen serverseitigen
|
||||
Job ohnehin nicht nutzbar.
|
||||
|
||||
## Nächster CF-Sync = neuer Job im selben Muster
|
||||
Modul in `jobs/` anlegen, Klasse importieren + `register_jobs(...)` im `jobs/__init__.py` ergänzen,
|
||||
`Meta.has_sensitive_variables=False` setzen, Git-Sync, enablen, Dry-Run, dann Schedule. Die Wurzel-
|
||||
`__init__.py` gilt schon.
|
||||
65
docs/handoff-20260912-tp25-ap2-messung-blockiert.md
Normal file
65
docs/handoff-20260912-tp25-ap2-messung-blockiert.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Handoff 2026-09-12 — TP25 „ap2 unterperformt": Messung blockiert (kein Manager-Zugriff)
|
||||
|
||||
**Kurz:** Die ap2-In-situ-Frage (2 m/−80 dBm) konnte **nicht** gemessen werden. Grund ist **kein**
|
||||
WLAN-/Gerätedefekt, sondern ein **fehlender Management-Pfad zum Manager `crs326-core`** von den
|
||||
verfügbaren Vantage-Points. Auf Christophs Entscheidung **vertagt**, kein Geräte-Write, SPOF nicht
|
||||
angefasst.
|
||||
|
||||
## Bestandsaufnahme (erledigt)
|
||||
|
||||
- Gitea #17 (TP25) = nur Zeiger, `status:wip`, Prosa im Repo. SSoT bestätigt.
|
||||
- Prosa `docs/teilprojekte.md` ab Zeile 1081 + Archiv-Langfassung gelesen.
|
||||
- Handoffs `20260902-fund-e` (Fund E geschlossen, 7.24.1 war die Ursache) und
|
||||
`20260903-kanalplan` (Kanalplan live, In-situ-Messung als einziger Rest offen) gelesen.
|
||||
- **Einziger offener TP25-Punkt bleibt: ap2 unterperformt.**
|
||||
|
||||
## Warum die Messung blockiert ist (live verifiziert, nicht geraten)
|
||||
|
||||
Registration-Table/Scan liegen unter CAPsMAN **nur am Manager** (`crs326-core`). Dieser ist von
|
||||
beiden Messpunkten nicht erreichbar:
|
||||
|
||||
**Vantage 1 — diese Session (Mac am dw-Standort):**
|
||||
- Default-GW `fritz.box` 10.95.10.1 → BF nur über **WG-Tunnel**; **Cloudflare WARP aktiv** (lief).
|
||||
- **ICMP zu ganz BF ok** (ap2, NAS, Nautobot, core — alle ~32 ms, 0 % Loss).
|
||||
- **Direktes TCP nach BF tot**: VLAN20-Hosts (NAS:22, Nautobot:8080, pve:8006) → `connect`
|
||||
kommt nie zustande (`connect=0.000`, `http=000`). MikroTik-Ports schienen bei `nc -z` „offen",
|
||||
aber jeder echte Handshake (SSH-kex, REST, HTTPS) wird **resettet** → das waren
|
||||
**WARP-lokale nc-Fehlmeldungen** (CLAUDE.md-Gotcha: `nc -z` falsch-positiv/-negativ).
|
||||
- ⇒ Von hier existiert **kein** TCP-Management-Pfad in BF. Der Pfad trägt gerade nur ICMP.
|
||||
Passt zum WARP-/Tunnel-Muster (WARP = QUIC-Proxy, kein ICMP; hier umgekehrt: nur ICMP kommt durch).
|
||||
|
||||
**Vantage 2 — mikromcp (DS923, im BF-LAN, kein WARP):**
|
||||
- `check_router_health` core → **Connect Timeout :80** (~10,5 s).
|
||||
- ap1/ap2 → **`other side closed` / `ECONNRESET`** (TCP an, Handshake zu).
|
||||
- `run_command` core → `Timed out waiting for handshake`; ap2 → `Connection lost before handshake`.
|
||||
- ⇒ Auch der on-LAN-Pfad erreicht die Flotte nicht. Mögliche Ursachen (von hier **nicht** trennbar,
|
||||
daher nicht entschieden): VLAN20-Firewall auf :80 (mgmt-input nur VLAN10/HA:8728/Nautobot:22/cf-mesh),
|
||||
mikromcp-Host-Netzproblem auf der DS923, oder real.
|
||||
|
||||
**Wichtig:** Der Core ist **nicht** nachweislich defekt — ICMP + Routing sind gesund. Der Defekt liegt
|
||||
im Zugangspfad, nicht (belegbar) am Gerät.
|
||||
|
||||
## Nebenbefund: Doku-Drift ap2-Kanal (nicht verifizierbar mangels Manager-Zugriff)
|
||||
|
||||
- CLAUDE.md + `teilprojekte.md`-Langfassung: ap2 = **ch44 / 5220** (2,4 GHz ch11).
|
||||
- Handoff 09-03: ap2 = **5300/5320** (ch60/64, DFS Band B) + ch11.
|
||||
- Was **live** läuft, ist offen. Beim nächsten Manager-Zugriff via
|
||||
`/interface wifi radio print` (Frequenz je Radio) klären und die Doku angleichen.
|
||||
|
||||
## Nächste Session — was zu tun ist
|
||||
|
||||
1. **Sauberen Pfad herstellen** (Christophs Wahl, offen): WARP trennen + retest, ODER aus einer
|
||||
**BF-LAN-Session** (macmini) messen, ODER zuerst **mikromcp/DS923-Erreichbarkeit** zur Flotte klären.
|
||||
2. Sobald Manager erreichbar, der Messplan aus Handoff 09-03 §„Aufstellorts-Messplan":
|
||||
- `/interface wifi radio print terse proplist=cap,radio-mac,interface` (Karten-Snapshot; wandert bei Rejoin).
|
||||
- `/interface wifi radio print` → aktuelle Frequenz/TX je Radio (ap2 ch prüfen, Doku-Drift oben).
|
||||
- `/interface wifi registration-table print terse where ssid=dirtyvader-main` → Signal/Rate der ap2-Clients.
|
||||
- `/interface wifi scan cap-wifiN duration=…` **am Manager** → 5-GHz-Umfeld an ap2 (Wiederholung des 08-24-Scans).
|
||||
- Ziel: −80 dBm@2 m einordnen (Platzierung/Antenne/TX vs. Kanal-Umfeld), mit Zahlen.
|
||||
3. **Gotchas** (CLAUDE.md/09-03): scan/registration-table nur am Manager · `list_wifi_interfaces`
|
||||
leakt PSKs (nicht benutzen) · `cap-wifiN`-Karte wandert · vor Client-Diagnose `uptime`+`grep " caps,"`.
|
||||
|
||||
## Grenze eingehalten
|
||||
|
||||
Kein Geräte-Write. Core (SPOF) nicht angefasst. WARP nicht getrennt (Christophs Client). Doku-Drift
|
||||
dokumentiert statt stillschweigend „korrigiert".
|
||||
6
docs/messdaten/tp25-runde-1er/ap-map.txt
Normal file
6
docs/messdaten/tp25-runde-1er/ap-map.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
cap-wifi1=ap2/5GHz
|
||||
cap-wifi2=ap3/5GHz
|
||||
cap-wifi3=ap1/5GHz
|
||||
cap-wifi4=ap3/2,4GHz
|
||||
cap-wifi5=ap1/2,4GHz
|
||||
cap-wifi6=ap2/2,4GHz
|
||||
2
docs/messdaten/tp25-runde-1er/geraete.txt
Normal file
2
docs/messdaten/tp25-runde-1er/geraete.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
iphone|10.40.10.196|F2:62:4C:E1:AF:09
|
||||
s22|10.40.10.178|2A:0D:B0:5D:AD:A7
|
||||
6
docs/messdaten/tp25-runde-1er/markers.csv
Normal file
6
docs/messdaten/tp25-runde-1er/markers.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
ts_epoch,ts_local,marker
|
||||
1788526676,14:57:56,PINM=off
|
||||
1788526735,14:58:55,PINM=off
|
||||
1788526763,14:59:23,PINM=off
|
||||
1788526765,14:59:25,PINM=off
|
||||
1788526770,14:59:30,PINM=s22|2A:0D:B0:5D:AD:A7|ap1|24
|
||||
|
1
docs/messdaten/tp25-runde-1er/phase.json
Normal file
1
docs/messdaten/tp25-runde-1er/phase.json
Normal file
@@ -0,0 +1 @@
|
||||
{"mode": "langzeit", "phase": "GEHWEG", "title": "Roaming-Messung l\u00e4uft", "instruction": "Aufzeichnung gestoppt.", "step": 0, "steps": 0, "ends": 0}
|
||||
26
docs/messdaten/tp25-runde-1er/sampler-iphone.csv
Normal file
26
docs/messdaten/tp25-runde-1er/sampler-iphone.csv
Normal file
@@ -0,0 +1,26 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788526644,14:57:24,14:57:24,41,472232,195392,cap-wifi3,-57,309700000,325000000,2800,2960,00:04:37,00:00:00
|
||||
1788526646,14:57:26,14:57:26,11,229864,36304,cap-wifi3,-57,309700000,325000000,2800,2960,00:04:39,00:00:00
|
||||
1788526648,14:57:28,14:57:28,8,132384,26968,cap-wifi3,-59,309700000,309700000,6160,6512,00:04:41,00:00:00
|
||||
1788526650,14:57:30,14:57:30,30,196672,48240,cap-wifi3,-59,309700000,344100000,6160,6512,00:04:43,00:00:00
|
||||
1788526652,14:57:32,14:57:32,12,131304,37448,cap-wifi3,-59,309700000,344100000,6160,6512,00:04:45,00:00:00
|
||||
1788526654,14:57:34,14:57:34,11,92000,18872,cap-wifi3,-59,309700000,412900000,5600,5920,00:04:47,00:00:00
|
||||
1788526656,14:57:36,14:57:36,12,130144,24840,cap-wifi3,-60,309700000,390000000,6048,6512,00:04:49,00:00:00
|
||||
1788526658,14:57:38,14:57:38,9,105160,20800,cap-wifi3,-60,309700000,390000000,6048,6512,00:04:51,00:00:00
|
||||
1788526660,14:57:40,14:57:40,14,177144,59112,cap-wifi3,-57,309700000,344100000,6048,6288,00:04:53,00:00:00
|
||||
1788526662,14:57:42,14:57:42,11,136152,39360,cap-wifi3,-59,309700000,325000000,5600,5920,00:04:55,00:00:00
|
||||
1788526664,14:57:44,14:57:44,7,132416,46304,cap-wifi3,-59,309700000,325000000,5600,5920,00:04:57,00:00:00
|
||||
1788526666,14:57:46,14:57:46,8,462016,41704,cap-wifi3,-60,309700000,390000000,5600,6296,00:04:59,00:00:00
|
||||
1788526668,14:57:48,14:57:48,11,129736,41416,cap-wifi3,-59,309700000,390000000,5600,5920,00:05:01,00:00:00
|
||||
1788526670,14:57:50,14:57:51,14,401784,54464,cap-wifi3,-59,309700000,390000000,5600,5920,00:05:03,00:00:00
|
||||
1788526672,14:57:52,14:57:53,8,146064,92728,cap-wifi3,-56,309700000,433300000,6640,7008,00:05:05,00:00:00
|
||||
1788526674,14:57:54,14:57:55,14,111952,31488,cap-wifi3,-59,309700000,433300000,6160,6512,00:05:07,00:00:00
|
||||
1788526677,14:57:57,14:57:57,9,123096,20552,cap-wifi3,-57,309700000,433300000,6160,6512,00:05:09,00:00:00
|
||||
1788526679,14:57:59,14:57:59,15,113008,17656,cap-wifi3,-57,309700000,433300000,6160,6512,00:05:11,00:00:00
|
||||
1788526681,14:58:01,14:58:01,16,172400,59040,cap-wifi3,-58,309700000,433300000,6160,6512,00:05:14,00:00:00
|
||||
1788526683,14:58:03,14:58:03,10,190968,57448,cap-wifi3,-59,309700000,433300000,5600,5920,00:05:16,00:00:00
|
||||
1788526685,14:58:05,14:58:05,8,183848,56872,cap-wifi3,-59,309700000,433300000,5600,5920,00:05:18,00:00:00
|
||||
1788526687,14:58:07,14:58:07,9,305320,47576,cap-wifi3,-59,309700000,487500000,5600,5920,00:05:20,00:00:00
|
||||
1788526689,14:58:09,14:58:09,20,331408,59856,cap-wifi3,-58,309700000,455800000,5600,5920,00:05:22,00:00:00
|
||||
1788526691,14:58:11,14:58:11,10,322448,65576,cap-wifi3,-58,309700000,455800000,5600,5920,00:05:24,00:00:00
|
||||
1788526692,14:58:12,RECONNECT
|
||||
|
1
docs/messdaten/tp25-runde-1er/sampler-iphone.out
Normal file
1
docs/messdaten/tp25-runde-1er/sampler-iphone.out
Normal file
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-1er/sampler-iphone.csv (Takt 2s, Client F2:62:4C:E1:AF:09)
|
||||
1
docs/messdaten/tp25-runde-1er/sampler-iphone.stderr.log
Normal file
1
docs/messdaten/tp25-runde-1er/sampler-iphone.stderr.log
Normal file
@@ -0,0 +1 @@
|
||||
14:58:12 Verbindung weg -- neuer Versuch in 2 s
|
||||
26
docs/messdaten/tp25-runde-1er/sampler-s22.csv
Normal file
26
docs/messdaten/tp25-runde-1er/sampler-s22.csv
Normal file
@@ -0,0 +1,26 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788526644,14:57:24,14:57:24,41,472232,195392,cap-wifi5,-61,137600000,229400000,2800,2960,01:04:55,00:00:00
|
||||
1788526646,14:57:26,14:57:26,11,229864,36304,cap-wifi5,-59,172100000,229400000,2800,2960,01:04:57,00:00:00
|
||||
1788526648,14:57:28,14:57:28,8,143088,22488,cap-wifi5,-60,172100000,229400000,2800,2368,01:04:59,00:00:00
|
||||
1788526650,14:57:30,14:57:30,30,192288,49440,cap-wifi5,-60,172100000,229400000,2800,2368,01:05:01,00:00:00
|
||||
1788526652,14:57:32,14:57:32,12,131304,37448,cap-wifi5,-60,172100000,229400000,3360,3552,01:05:03,00:00:00
|
||||
1788526654,14:57:34,14:57:34,11,92000,18872,cap-wifi5,-60,172100000,229400000,2800,2960,01:05:05,00:00:00
|
||||
1788526656,14:57:36,14:57:36,12,130144,24840,cap-wifi5,-60,172100000,229400000,2800,2960,01:05:07,00:00:00
|
||||
1788526658,14:57:38,14:57:38,9,105160,20800,cap-wifi5,-59,129000000,258100000,3856,2960,01:05:09,00:00:00
|
||||
1788526660,14:57:40,14:57:40,14,177144,59112,cap-wifi5,-58,114700000,229400000,7888,15664,01:05:11,00:00:00
|
||||
1788526662,14:57:42,14:57:42,11,136152,39360,cap-wifi5,-58,114700000,229400000,7888,15664,01:05:13,00:00:00
|
||||
1788526664,14:57:44,14:57:45,7,132416,46304,cap-wifi5,-57,114700000,206500000,3360,2960,01:05:15,00:00:00
|
||||
1788526666,14:57:46,14:57:47,8,462016,41704,cap-wifi5,-57,114700000,206500000,2800,2960,01:05:17,00:00:00
|
||||
1788526669,14:57:49,14:57:49,11,129736,41416,cap-wifi5,-57,154900000,172100000,3360,3552,01:05:19,00:00:00
|
||||
1788526671,14:57:51,14:57:51,14,401784,54464,cap-wifi5,-57,154900000,172100000,3360,3552,01:05:21,00:00:00
|
||||
1788526673,14:57:53,14:57:53,8,146064,92728,cap-wifi5,-58,154900000,206500000,2800,2960,01:05:23,00:00:00
|
||||
1788526675,14:57:55,14:57:55,14,111952,31488,cap-wifi5,-58,154900000,229400000,2800,2960,01:05:26,00:00:00
|
||||
1788526677,14:57:57,14:57:57,9,123096,20552,cap-wifi5,-58,154900000,229400000,2800,2960,01:05:28,00:00:00
|
||||
1788526679,14:57:59,14:57:59,17,113008,17656,cap-wifi5,-58,103200000,229400000,2800,2960,01:05:30,00:00:00
|
||||
1788526681,14:58:01,14:58:01,9,172400,59040,cap-wifi5,-58,103200000,206500000,3248,3328,01:05:32,00:00:00
|
||||
1788526683,14:58:03,14:58:03,10,190968,57448,cap-wifi5,-58,103200000,206500000,3248,3328,01:05:34,00:00:00
|
||||
1788526685,14:58:05,14:58:05,10,183848,56872,cap-wifi5,-58,103200000,206500000,2800,2960,01:05:36,00:00:00
|
||||
1788526687,14:58:07,14:58:07,9,305320,47576,cap-wifi5,-59,103200000,229400000,2800,2960,01:05:38,00:00:00
|
||||
1788526689,14:58:09,14:58:09,20,331408,59856,cap-wifi5,-59,103200000,229400000,2800,2960,01:05:40,00:00:00
|
||||
1788526691,14:58:11,14:58:11,10,322448,65576,cap-wifi5,-58,103200000,206500000,2800,2960,01:05:42,00:00:00
|
||||
1788526692,14:58:12,RECONNECT
|
||||
|
1
docs/messdaten/tp25-runde-1er/sampler-s22.out
Normal file
1
docs/messdaten/tp25-runde-1er/sampler-s22.out
Normal file
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-1er/sampler-s22.csv (Takt 2s, Client 2A:0D:B0:5D:AD:A7)
|
||||
1
docs/messdaten/tp25-runde-1er/sampler-s22.stderr.log
Normal file
1
docs/messdaten/tp25-runde-1er/sampler-s22.stderr.log
Normal file
@@ -0,0 +1 @@
|
||||
14:58:12 Verbindung weg -- neuer Versuch in 2 s
|
||||
242
docs/messdaten/tp25-runde-1er/walk-ping-iphone.csv
Normal file
242
docs/messdaten/tp25-runde-1er/walk-ping-iphone.csv
Normal file
@@ -0,0 +1,242 @@
|
||||
ts_local,seq,ms
|
||||
14:57:24,0,3ms102us
|
||||
14:57:24,1,2ms682us
|
||||
14:57:25,2,2ms739us
|
||||
14:57:25,3,2ms889us
|
||||
14:57:25,4,2ms955us
|
||||
14:57:25,5,4ms434us
|
||||
14:57:25,6,4ms59us
|
||||
14:57:26,7,3ms540us
|
||||
14:57:26,8,98ms220us
|
||||
14:57:26,9,2ms841us
|
||||
14:57:26,10,95ms173us
|
||||
14:57:26,11,2ms688us
|
||||
14:57:27,12,113ms888us
|
||||
14:57:27,13,4ms866us
|
||||
14:57:27,14,2ms909us
|
||||
14:57:27,15,2ms776us
|
||||
14:57:27,16,2ms572us
|
||||
14:57:28,17,2ms931us
|
||||
14:57:28,18,2ms663us
|
||||
14:57:28,19,2ms796us
|
||||
14:57:28,20,2ms736us
|
||||
14:57:28,21,2ms826us
|
||||
14:57:29,22,2ms778us
|
||||
14:57:29,23,2ms741us
|
||||
14:57:29,24,2ms904us
|
||||
14:57:29,25,2ms744us
|
||||
14:57:29,26,2ms845us
|
||||
14:57:30,27,2ms850us
|
||||
14:57:30,28,2ms746us
|
||||
14:57:30,29,2ms973us
|
||||
14:57:30,30,2ms907us
|
||||
14:57:30,31,2ms771us
|
||||
14:57:31,32,2ms778us
|
||||
14:57:31,33,2ms793us
|
||||
14:57:31,34,2ms823us
|
||||
14:57:31,35,2ms717us
|
||||
14:57:31,36,5ms311us
|
||||
14:57:32,37,2ms752us
|
||||
14:57:32,38,2ms799us
|
||||
14:57:32,39,2ms964us
|
||||
14:57:32,40,2ms760us
|
||||
14:57:32,41,3ms53us
|
||||
14:57:33,42,2ms775us
|
||||
14:57:33,43,2ms793us
|
||||
14:57:33,44,4ms125us
|
||||
14:57:33,45,2ms696us
|
||||
14:57:33,46,2ms686us
|
||||
14:57:34,47,2ms738us
|
||||
14:57:34,48,2ms824us
|
||||
14:57:34,49,2ms607us
|
||||
14:57:34,50,2ms944us
|
||||
14:57:34,51,2ms854us
|
||||
14:57:35,52,2ms724us
|
||||
14:57:35,53,3ms453us
|
||||
14:57:35,54,3ms417us
|
||||
14:57:35,55,3ms535us
|
||||
14:57:35,56,2ms719us
|
||||
14:57:36,57,4ms498us
|
||||
14:57:36,58,2ms706us
|
||||
14:57:36,59,4ms279us
|
||||
14:57:36,60,2ms836us
|
||||
14:57:36,61,2ms646us
|
||||
14:57:37,62,2ms873us
|
||||
14:57:37,63,2ms782us
|
||||
14:57:37,64,2ms624us
|
||||
14:57:37,65,2ms881us
|
||||
14:57:37,66,2ms716us
|
||||
14:57:38,67,2ms763us
|
||||
14:57:38,68,2ms833us
|
||||
14:57:38,69,2ms879us
|
||||
14:57:38,70,2ms851us
|
||||
14:57:38,71,2ms777us
|
||||
14:57:39,72,2ms937us
|
||||
14:57:39,73,2ms821us
|
||||
14:57:39,74,2ms729us
|
||||
14:57:39,75,2ms892us
|
||||
14:57:39,76,2ms729us
|
||||
14:57:40,77,2ms755us
|
||||
14:57:40,78,2ms932us
|
||||
14:57:40,79,2ms701us
|
||||
14:57:40,80,2ms662us
|
||||
14:57:40,81,2ms651us
|
||||
14:57:41,82,5ms991us
|
||||
14:57:41,83,2ms728us
|
||||
14:57:41,84,2ms756us
|
||||
14:57:41,85,2ms716us
|
||||
14:57:41,86,2ms707us
|
||||
14:57:42,87,2ms785us
|
||||
14:57:42,88,2ms594us
|
||||
14:57:42,89,2ms747us
|
||||
14:57:42,90,2ms712us
|
||||
14:57:42,91,3ms258us
|
||||
14:57:43,92,2ms727us
|
||||
14:57:43,93,2ms623us
|
||||
14:57:43,94,2ms723us
|
||||
14:57:43,95,2ms749us
|
||||
14:57:43,96,2ms700us
|
||||
14:57:44,97,2ms723us
|
||||
14:57:44,98,2ms735us
|
||||
14:57:44,99,3ms646us
|
||||
14:57:44,100,2ms718us
|
||||
14:57:44,101,2ms740us
|
||||
14:57:45,102,2ms768us
|
||||
14:57:45,103,2ms663us
|
||||
14:57:45,104,2ms639us
|
||||
14:57:45,105,2ms731us
|
||||
14:57:45,106,3ms290us
|
||||
14:57:46,107,2ms822us
|
||||
14:57:46,108,2ms844us
|
||||
14:57:46,109,2ms617us
|
||||
14:57:46,110,2ms734us
|
||||
14:57:46,111,3ms447us
|
||||
14:57:47,112,3ms169us
|
||||
14:57:47,113,3ms247us
|
||||
14:57:47,114,2ms564us
|
||||
14:57:47,115,4ms516us
|
||||
14:57:47,116,2ms623us
|
||||
14:57:48,117,2ms675us
|
||||
14:57:48,118,2ms877us
|
||||
14:57:48,119,3ms310us
|
||||
14:57:48,120,2ms851us
|
||||
14:57:48,121,2ms803us
|
||||
14:57:49,122,7ms998us
|
||||
14:57:49,123,2ms887us
|
||||
14:57:49,124,2ms852us
|
||||
14:57:49,125,2ms846us
|
||||
14:57:49,126,2ms899us
|
||||
14:57:50,127,2ms913us
|
||||
14:57:50,128,2ms680us
|
||||
14:57:50,129,2ms715us
|
||||
14:57:50,130,3ms374us
|
||||
14:57:50,131,2ms670us
|
||||
14:57:51,132,3ms148us
|
||||
14:57:51,133,2ms932us
|
||||
14:57:51,134,2ms831us
|
||||
14:57:51,135,4ms780us
|
||||
14:57:51,136,2ms911us
|
||||
14:57:52,137,3ms85us
|
||||
14:57:52,138,3ms589us
|
||||
14:57:52,139,2ms697us
|
||||
14:57:52,140,4ms876us
|
||||
14:57:52,141,2ms867us
|
||||
14:57:53,142,3ms283us
|
||||
14:57:53,143,2ms710us
|
||||
14:57:53,144,2ms801us
|
||||
14:57:53,145,2ms928us
|
||||
14:57:53,146,2ms640us
|
||||
14:57:54,147,2ms678us
|
||||
14:57:54,148,4ms976us
|
||||
14:57:54,149,3ms408us
|
||||
14:57:54,150,2ms706us
|
||||
14:57:54,151,2ms827us
|
||||
14:57:55,152,2ms884us
|
||||
14:57:55,153,2ms855us
|
||||
14:57:55,154,2ms787us
|
||||
14:57:55,155,2ms695us
|
||||
14:57:55,156,2ms902us
|
||||
14:57:56,157,2ms749us
|
||||
14:57:56,158,2ms838us
|
||||
14:57:56,159,3ms937us
|
||||
14:57:57,160,3ms43us
|
||||
14:57:57,161,2ms870us
|
||||
14:57:57,162,3ms357us
|
||||
14:57:57,163,2ms756us
|
||||
14:57:57,164,2ms679us
|
||||
14:57:57,165,2ms863us
|
||||
14:57:57,166,2ms768us
|
||||
14:57:58,167,2ms858us
|
||||
14:57:58,168,3ms30us
|
||||
14:57:58,169,2ms677us
|
||||
14:57:58,170,2ms725us
|
||||
14:57:58,171,2ms919us
|
||||
14:57:59,172,2ms688us
|
||||
14:57:59,173,2ms821us
|
||||
14:57:59,174,2ms805us
|
||||
14:57:59,175,2ms709us
|
||||
14:57:59,176,2ms989us
|
||||
14:58:00,177,2ms589us
|
||||
14:58:00,178,3ms835us
|
||||
14:58:00,179,3ms194us
|
||||
14:58:00,180,2ms662us
|
||||
14:58:00,181,2ms686us
|
||||
14:58:01,182,2ms704us
|
||||
14:58:01,183,2ms752us
|
||||
14:58:01,184,2ms656us
|
||||
14:58:01,185,2ms904us
|
||||
14:58:01,186,2ms823us
|
||||
14:58:02,187,2ms656us
|
||||
14:58:02,188,2ms813us
|
||||
14:58:02,189,2ms644us
|
||||
14:58:02,190,2ms782us
|
||||
14:58:02,191,2ms722us
|
||||
14:58:03,192,2ms674us
|
||||
14:58:03,193,5ms657us
|
||||
14:58:03,194,4ms701us
|
||||
14:58:03,195,2ms772us
|
||||
14:58:03,196,2ms661us
|
||||
14:58:04,197,2ms660us
|
||||
14:58:04,198,2ms859us
|
||||
14:58:04,199,2ms800us
|
||||
14:58:04,200,2ms706us
|
||||
14:58:04,201,2ms847us
|
||||
14:58:05,202,2ms625us
|
||||
14:58:05,203,2ms816us
|
||||
14:58:05,204,2ms703us
|
||||
14:58:05,205,2ms818us
|
||||
14:58:05,206,3ms162us
|
||||
14:58:06,207,2ms673us
|
||||
14:58:06,208,2ms781us
|
||||
14:58:06,209,2ms607us
|
||||
14:58:06,210,2ms990us
|
||||
14:58:06,211,2ms602us
|
||||
14:58:07,212,2ms711us
|
||||
14:58:07,213,2ms819us
|
||||
14:58:07,214,2ms757us
|
||||
14:58:07,215,2ms605us
|
||||
14:58:07,216,2ms770us
|
||||
14:58:08,217,2ms682us
|
||||
14:58:08,218,4ms824us
|
||||
14:58:08,219,2ms623us
|
||||
14:58:08,220,2ms566us
|
||||
14:58:08,221,2ms724us
|
||||
14:58:09,222,3ms737us
|
||||
14:58:09,223,3ms273us
|
||||
14:58:09,224,2ms809us
|
||||
14:58:09,225,2ms619us
|
||||
14:58:09,226,2ms709us
|
||||
14:58:10,227,2ms909us
|
||||
14:58:10,228,2ms707us
|
||||
14:58:10,229,2ms909us
|
||||
14:58:10,230,2ms610us
|
||||
14:58:10,231,3ms251us
|
||||
14:58:11,232,2ms689us
|
||||
14:58:11,233,2ms714us
|
||||
14:58:11,234,2ms680us
|
||||
14:58:11,235,2ms644us
|
||||
14:58:11,236,2ms665us
|
||||
14:58:12,237,3ms326us
|
||||
14:58:12,238,2ms749us
|
||||
14:58:12,239,2ms713us
|
||||
14:58:12,,RECONNECT
|
||||
|
238
docs/messdaten/tp25-runde-1er/walk-ping-s22.csv
Normal file
238
docs/messdaten/tp25-runde-1er/walk-ping-s22.csv
Normal file
@@ -0,0 +1,238 @@
|
||||
ts_local,seq,ms
|
||||
14:57:24,0,
|
||||
14:57:25,1,
|
||||
14:57:25,2,
|
||||
14:57:25,3,
|
||||
14:57:25,4,
|
||||
14:57:25,5,
|
||||
14:57:26,6,
|
||||
14:57:26,7,
|
||||
14:57:26,8,
|
||||
14:57:26,9,
|
||||
14:57:26,10,
|
||||
14:57:27,11,
|
||||
14:57:27,12,
|
||||
14:57:27,13,
|
||||
14:57:27,14,
|
||||
14:57:27,15,unre...
|
||||
14:57:28,16,
|
||||
14:57:28,17,
|
||||
14:57:28,18,
|
||||
14:57:28,19,
|
||||
14:57:28,20,
|
||||
14:57:29,21,
|
||||
14:57:29,22,
|
||||
14:57:29,23,
|
||||
14:57:29,24,
|
||||
14:57:29,25,
|
||||
14:57:30,26,
|
||||
14:57:30,27,
|
||||
14:57:30,28,
|
||||
14:57:30,29,
|
||||
14:57:30,30,
|
||||
14:57:31,31,unre...
|
||||
14:57:31,32,
|
||||
14:57:31,33,
|
||||
14:57:31,34,
|
||||
14:57:31,35,
|
||||
14:57:32,36,
|
||||
14:57:32,37,
|
||||
14:57:32,38,
|
||||
14:57:32,39,
|
||||
14:57:32,40,
|
||||
14:57:33,41,
|
||||
14:57:33,42,
|
||||
14:57:33,43,
|
||||
14:57:33,44,
|
||||
14:57:33,45,
|
||||
14:57:34,46,
|
||||
14:57:34,47,unre...
|
||||
14:57:34,48,
|
||||
14:57:34,49,
|
||||
14:57:34,50,
|
||||
14:57:35,51,
|
||||
14:57:35,52,
|
||||
14:57:35,53,
|
||||
14:57:35,54,
|
||||
14:57:35,55,
|
||||
14:57:36,56,
|
||||
14:57:36,57,
|
||||
14:57:36,58,
|
||||
14:57:36,59,
|
||||
14:57:37,60,
|
||||
14:57:37,61,
|
||||
14:57:37,62,
|
||||
14:57:37,63,unre...
|
||||
14:57:38,64,
|
||||
14:57:38,65,
|
||||
14:57:38,66,
|
||||
14:57:38,67,
|
||||
14:57:38,68,
|
||||
14:57:38,69,
|
||||
14:57:39,70,
|
||||
14:57:39,71,
|
||||
14:57:39,72,
|
||||
14:57:39,73,
|
||||
14:57:39,74,
|
||||
14:57:40,75,
|
||||
14:57:40,76,
|
||||
14:57:40,77,
|
||||
14:57:40,78,
|
||||
14:57:40,79,unre...
|
||||
14:57:41,80,
|
||||
14:57:41,81,
|
||||
14:57:41,82,
|
||||
14:57:41,83,
|
||||
14:57:41,84,
|
||||
14:57:42,85,
|
||||
14:57:42,86,
|
||||
14:57:42,87,
|
||||
14:57:42,88,
|
||||
14:57:42,89,
|
||||
14:57:43,90,
|
||||
14:57:43,91,
|
||||
14:57:43,92,
|
||||
14:57:43,93,
|
||||
14:57:43,94,
|
||||
14:57:43,95,unre...
|
||||
14:57:44,96,
|
||||
14:57:44,97,
|
||||
14:57:44,98,
|
||||
14:57:44,99,
|
||||
14:57:45,100,
|
||||
14:57:45,101,
|
||||
14:57:45,102,
|
||||
14:57:45,103,
|
||||
14:57:45,104,
|
||||
14:57:46,105,
|
||||
14:57:46,106,
|
||||
14:57:46,107,
|
||||
14:57:46,108,
|
||||
14:57:46,109,
|
||||
14:57:47,110,
|
||||
14:57:47,111,unre...
|
||||
14:57:47,112,
|
||||
14:57:47,113,
|
||||
14:57:47,114,
|
||||
14:57:48,115,
|
||||
14:57:48,116,
|
||||
14:57:48,117,
|
||||
14:57:48,118,
|
||||
14:57:49,119,
|
||||
14:57:49,120,
|
||||
14:57:49,121,
|
||||
14:57:49,122,
|
||||
14:57:49,123,
|
||||
14:57:50,124,
|
||||
14:57:50,125,
|
||||
14:57:50,126,
|
||||
14:57:50,127,unre...
|
||||
14:57:50,128,
|
||||
14:57:51,129,
|
||||
14:57:51,130,
|
||||
14:57:51,131,
|
||||
14:57:51,132,
|
||||
14:57:51,133,
|
||||
14:57:52,134,
|
||||
14:57:52,135,
|
||||
14:57:52,136,
|
||||
14:57:52,137,
|
||||
14:57:52,138,
|
||||
14:57:53,139,
|
||||
14:57:53,140,
|
||||
14:57:53,141,
|
||||
14:57:53,142,
|
||||
14:57:53,143,unre...
|
||||
14:57:54,144,
|
||||
14:57:54,145,
|
||||
14:57:54,146,
|
||||
14:57:54,147,
|
||||
14:57:54,148,
|
||||
14:57:55,149,
|
||||
14:57:55,150,
|
||||
14:57:55,151,
|
||||
14:57:55,152,
|
||||
14:57:55,153,
|
||||
14:57:56,154,
|
||||
14:57:56,155,
|
||||
14:57:56,156,
|
||||
14:57:57,157,
|
||||
14:57:57,158,
|
||||
14:57:57,159,unre...
|
||||
14:57:57,160,
|
||||
14:57:57,161,
|
||||
14:57:57,162,
|
||||
14:57:57,163,
|
||||
14:57:58,164,
|
||||
14:57:58,165,
|
||||
14:57:58,166,
|
||||
14:57:58,167,
|
||||
14:57:58,168,
|
||||
14:57:59,169,
|
||||
14:57:59,170,
|
||||
14:57:59,171,
|
||||
14:57:59,172,
|
||||
14:57:59,173,
|
||||
14:58:00,174,
|
||||
14:58:00,175,unre...
|
||||
14:58:00,176,
|
||||
14:58:00,177,
|
||||
14:58:00,178,
|
||||
14:58:01,179,
|
||||
14:58:01,180,
|
||||
14:58:01,181,
|
||||
14:58:01,182,
|
||||
14:58:01,183,
|
||||
14:58:02,184,
|
||||
14:58:02,185,
|
||||
14:58:02,186,
|
||||
14:58:02,187,
|
||||
14:58:02,188,
|
||||
14:58:03,189,
|
||||
14:58:03,190,
|
||||
14:58:03,191,unre...
|
||||
14:58:03,192,
|
||||
14:58:03,193,
|
||||
14:58:04,194,
|
||||
14:58:04,195,
|
||||
14:58:04,196,
|
||||
14:58:04,197,
|
||||
14:58:04,198,
|
||||
14:58:05,199,
|
||||
14:58:05,200,
|
||||
14:58:05,201,
|
||||
14:58:05,202,
|
||||
14:58:05,203,
|
||||
14:58:06,204,
|
||||
14:58:06,205,
|
||||
14:58:06,206,
|
||||
14:58:06,207,unre...
|
||||
14:58:07,208,
|
||||
14:58:07,209,
|
||||
14:58:07,210,
|
||||
14:58:07,211,
|
||||
14:58:07,212,
|
||||
14:58:08,213,
|
||||
14:58:08,214,
|
||||
14:58:08,215,
|
||||
14:58:08,216,
|
||||
14:58:08,217,
|
||||
14:58:09,218,
|
||||
14:58:09,219,
|
||||
14:58:09,220,
|
||||
14:58:09,221,
|
||||
14:58:09,222,
|
||||
14:58:09,223,unre...
|
||||
14:58:10,224,
|
||||
14:58:10,225,
|
||||
14:58:10,226,
|
||||
14:58:10,227,
|
||||
14:58:11,228,
|
||||
14:58:11,229,
|
||||
14:58:11,230,
|
||||
14:58:11,231,
|
||||
14:58:11,232,
|
||||
14:58:12,233,
|
||||
14:58:12,234,
|
||||
14:58:12,235,
|
||||
14:58:12,,RECONNECT
|
||||
|
6
docs/messdaten/tp25-runde-dauerping/ap-map.txt
Normal file
6
docs/messdaten/tp25-runde-dauerping/ap-map.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
cap-wifi1=ap2/5GHz
|
||||
cap-wifi2=ap3/5GHz
|
||||
cap-wifi3=ap1/5GHz
|
||||
cap-wifi4=ap3/2,4GHz
|
||||
cap-wifi5=ap1/2,4GHz
|
||||
cap-wifi6=ap2/2,4GHz
|
||||
@@ -0,0 +1 @@
|
||||
ts_epoch,ts_local,marker
|
||||
|
@@ -0,0 +1,43 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788526610,14:56:50,14:56:50,50,160216,1109704,cap-wifi2,-69,137600000,275300000,45848,2240,01:04:23,00:00:00
|
||||
1788526612,14:56:52,14:56:52,6,151312,62480,cap-wifi2,-69,137600000,275300000,45848,2240,01:04:25,00:00:00
|
||||
1788526614,14:56:54,14:56:54,15,127416,44832,cap-wifi2,-69,137600000,309700000,36152,6320,01:04:27,00:00:00
|
||||
1788526616,14:56:56,14:56:56,4,127712,21960,cap-wifi2,-69,103200000,325000000,42008,9736,01:04:29,00:00:00
|
||||
1788526618,14:56:58,14:56:58,9,157888,29816,cap-wifi2,-69,103200000,325000000,42008,9736,01:04:31,00:00:00
|
||||
1788526620,14:57:00,14:57:00,16,322208,124400,cap-wifi2,-69,103200000,344100000,123600,58608,01:04:33,00:00:00
|
||||
1788526622,14:57:02,14:57:03,10,451416,4332552,cap-wifi2,-69,137600000,275300000,193568,29704,01:04:35,00:00:00
|
||||
1788526624,14:57:04,14:57:05,9,398720,136640,cap-wifi2,-69,137600000,292500000,40792,7440,01:04:37,00:00:00
|
||||
1788526627,14:57:07,14:57:07,15,947800,446984,cap-wifi2,-69,137600000,292500000,40792,7440,01:04:40,00:00:00
|
||||
1788526629,14:57:09,14:57:09,12,7610296,3321592,cap-wifi2,-69,154900000,292500000,89400,14304,01:04:42,00:00:00
|
||||
1788526631,14:57:11,14:57:11,18,2720136,2091232,cap-wifi2,-69,103200000,275300000,69264,10760,01:04:44,00:00:00
|
||||
1788526633,14:57:13,14:57:13,9,2261568,2680088,cap-wifi2,-69,103200000,275300000,69264,10760,01:04:46,00:00:00
|
||||
1788526635,14:57:15,14:57:15,7,108584,42016,cap-wifi2,-69,103200000,309700000,78112,11920,01:04:48,00:00:00
|
||||
1788526637,14:57:17,14:57:17,4,309312,51096,cap-wifi2,-68,103200000,309700000,117392,10152,01:04:50,00:00:00
|
||||
1788526639,14:57:19,14:57:19,14,309864,66576,cap-wifi2,-68,103200000,309700000,117392,10152,01:04:52,00:00:00
|
||||
1788526641,14:57:21,14:57:21,6,150056,22800,cap-wifi2,-68,103200000,309700000,53888,10272,01:04:54,00:00:00
|
||||
1788526643,14:57:23,14:57:23,14,510016,213944,cap-wifi2,-68,103200000,309700000,61328,9088,01:04:56,00:00:00
|
||||
1788526645,14:57:25,14:57:25,19,507656,169768,cap-wifi2,-68,103200000,309700000,61328,9088,01:04:58,00:00:00
|
||||
1788526647,14:57:27,14:57:27,9,136752,33856,cap-wifi2,-69,103200000,309700000,41640,8560,01:05:00,00:00:00
|
||||
1788526649,14:57:29,14:57:29,18,143088,22488,cap-wifi2,-69,103200000,292500000,61120,8192,01:05:02,00:00:00
|
||||
1788526651,14:57:31,14:57:31,15,192288,49440,cap-wifi2,-69,103200000,292500000,61120,8192,01:05:04,00:00:00
|
||||
1788526653,14:57:33,14:57:33,9,131304,37448,cap-wifi2,-69,137600000,309700000,57760,8136,01:05:06,00:00:00
|
||||
1788526655,14:57:35,14:57:35,11,92000,18872,cap-wifi2,-69,137600000,344100000,56408,8592,01:05:08,00:00:00
|
||||
1788526657,14:57:37,14:57:37,9,130144,24840,cap-wifi2,-69,137600000,344100000,56408,8592,01:05:10,00:00:00
|
||||
1788526659,14:57:39,14:57:39,20,105160,20800,cap-wifi2,-69,137600000,325000000,19344,5200,01:05:12,00:00:00
|
||||
1788526661,14:57:41,14:57:41,11,177144,59112,cap-wifi2,-71,154900000,275300000,111184,14496,01:05:14,00:00:00
|
||||
1788526663,14:57:43,14:57:43,16,136152,39360,cap-wifi2,-71,154900000,275300000,111184,14496,01:05:16,00:00:00
|
||||
1788526665,14:57:45,14:57:45,16,132416,46304,cap-wifi2,-70,154900000,309700000,44928,8560,01:05:18,00:00:00
|
||||
1788526667,14:57:47,14:57:47,11,462016,41704,cap-wifi2,-70,154900000,309700000,397536,18704,01:05:20,00:00:00
|
||||
1788526669,14:57:49,14:57:49,24,129736,41416,cap-wifi2,-70,154900000,309700000,397536,18704,01:05:22,00:00:00
|
||||
1788526671,14:57:51,14:57:51,7,401784,54464,cap-wifi2,-76,103200000,206500000,44784,8560,01:05:24,00:00:00
|
||||
1788526673,14:57:53,14:57:53,14,101992,21720,cap-wifi2,-69,103200000,292500000,55400,9120,01:05:26,00:00:00
|
||||
1788526675,14:57:55,14:57:55,14,152504,61272,cap-wifi2,-69,103200000,292500000,55400,9120,01:05:28,00:00:00
|
||||
1788526677,14:57:57,14:57:57,22,130520,26552,cap-wifi2,-70,103200000,260000000,55304,10816,01:05:30,00:00:00
|
||||
1788526679,14:57:59,14:57:59,17,155408,24688,cap-wifi2,-69,103200000,275300000,58480,8720,01:05:32,00:00:00
|
||||
1788526681,14:58:01,14:58:01,9,244456,41424,cap-wifi2,-69,103200000,275300000,58480,8720,01:05:34,00:00:00
|
||||
1788526683,14:58:03,14:58:03,10,115640,26032,cap-wifi2,-69,103200000,260000000,38208,22096,01:05:36,00:00:00
|
||||
1788526685,14:58:05,14:58:05,10,154824,24456,cap-wifi2,-70,137600000,260000000,65000,8000,01:05:38,00:00:00
|
||||
1788526687,14:58:07,14:58:07,9,135144,25000,cap-wifi2,-70,137600000,260000000,65000,8000,01:05:40,00:00:00
|
||||
1788526689,14:58:09,14:58:10,20,122800,29936,cap-wifi2,-68,137600000,275300000,18856,4048,01:05:42,00:00:00
|
||||
1788526691,14:58:11,14:58:12,10,152160,65768,cap-wifi2,-68,137600000,206500000,40064,12024,01:05:44,00:00:00
|
||||
1788526692,14:58:12,RECONNECT
|
||||
|
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-ipad.csv (Takt 2s, Client CA:B8:D4:3F:8A:81)
|
||||
@@ -0,0 +1,43 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788526610,14:56:50,14:56:50,50,160216,1109704,cap-wifi3,-58,309700000,412900000,0,0,00:04:03,00:00:03.010
|
||||
1788526612,14:56:52,14:56:52,6,151312,62480,cap-wifi3,-57,309700000,412900000,0,0,00:04:05,00:00:00
|
||||
1788526614,14:56:54,14:56:54,15,127416,44832,cap-wifi3,-57,309700000,412900000,2800,2960,00:04:07,00:00:00
|
||||
1788526616,14:56:56,14:56:56,4,127712,21960,cap-wifi3,-57,309700000,412900000,2800,2960,00:04:09,00:00:00
|
||||
1788526618,14:56:58,14:56:58,9,157888,29816,cap-wifi3,-57,309700000,412900000,3248,3552,00:04:11,00:00:00
|
||||
1788526620,14:57:00,14:57:00,16,322208,124400,cap-wifi3,-57,344100000,325000000,3360,3552,00:04:13,00:00:00
|
||||
1788526622,14:57:02,14:57:03,10,451416,4332552,cap-wifi3,-58,344100000,344100000,2800,2960,00:04:15,00:00:00
|
||||
1788526624,14:57:04,14:57:05,9,398720,136640,cap-wifi3,-58,344100000,344100000,2800,2960,00:04:17,00:00:00
|
||||
1788526627,14:57:07,14:57:07,15,947800,446984,cap-wifi3,-59,344100000,325000000,3360,3552,00:04:20,00:00:00
|
||||
1788526629,14:57:09,14:57:09,12,7610296,3321592,cap-wifi3,-58,344100000,344100000,2800,2960,00:04:22,00:00:00
|
||||
1788526631,14:57:11,14:57:11,18,2720136,2091232,cap-wifi3,-58,344100000,344100000,2800,2960,00:04:24,00:00:00
|
||||
1788526633,14:57:13,14:57:13,9,2261568,2680088,cap-wifi3,-57,344100000,325000000,3360,3552,00:04:26,00:00:00
|
||||
1788526635,14:57:15,14:57:15,7,108584,42016,cap-wifi3,-57,344100000,344100000,2800,2960,00:04:28,00:00:00
|
||||
1788526637,14:57:17,14:57:17,4,309312,51096,cap-wifi3,-57,344100000,344100000,2800,2960,00:04:30,00:00:00
|
||||
1788526639,14:57:19,14:57:19,14,309864,66576,cap-wifi3,-58,344100000,325000000,2800,2960,00:04:32,00:00:00
|
||||
1788526641,14:57:21,14:57:21,6,150056,22800,cap-wifi3,-57,309700000,344100000,3808,4000,00:04:34,00:00:00
|
||||
1788526643,14:57:23,14:57:23,14,510016,213944,cap-wifi3,-57,309700000,344100000,3808,4000,00:04:36,00:00:00
|
||||
1788526645,14:57:25,14:57:25,19,507656,169768,cap-wifi3,-57,309700000,325000000,2800,2960,00:04:38,00:00:00
|
||||
1788526647,14:57:27,14:57:27,9,136752,33856,cap-wifi3,-59,309700000,309700000,6160,6512,00:04:40,00:00:00
|
||||
1788526649,14:57:29,14:57:29,18,143088,22488,cap-wifi3,-59,309700000,309700000,6160,6512,00:04:42,00:00:00
|
||||
1788526651,14:57:31,14:57:31,15,192288,49440,cap-wifi3,-59,309700000,344100000,6160,6512,00:04:44,00:00:00
|
||||
1788526653,14:57:33,14:57:33,9,131304,37448,cap-wifi3,-59,309700000,412900000,5600,5920,00:04:46,00:00:00
|
||||
1788526655,14:57:35,14:57:35,11,92000,18872,cap-wifi3,-59,309700000,412900000,5600,5920,00:04:48,00:00:00
|
||||
1788526657,14:57:37,14:57:37,9,130144,24840,cap-wifi3,-60,309700000,390000000,6048,6512,00:04:50,00:00:00
|
||||
1788526659,14:57:39,14:57:39,20,105160,20800,cap-wifi3,-57,309700000,344100000,6048,6288,00:04:52,00:00:00
|
||||
1788526661,14:57:41,14:57:41,11,177144,59112,cap-wifi3,-57,309700000,344100000,6048,6288,00:04:54,00:00:00
|
||||
1788526663,14:57:43,14:57:43,16,136152,39360,cap-wifi3,-59,309700000,325000000,5600,5920,00:04:56,00:00:00
|
||||
1788526665,14:57:45,14:57:45,16,132416,46304,cap-wifi3,-60,309700000,390000000,5600,6296,00:04:58,00:00:00
|
||||
1788526667,14:57:47,14:57:47,11,462016,41704,cap-wifi3,-60,309700000,390000000,5600,6296,00:05:00,00:00:00
|
||||
1788526669,14:57:49,14:57:49,24,129736,41416,cap-wifi3,-59,309700000,390000000,5600,5920,00:05:02,00:00:00
|
||||
1788526671,14:57:51,14:57:51,7,234376,122480,cap-wifi3,-56,309700000,433300000,6640,7008,00:05:04,00:00:00
|
||||
1788526673,14:57:53,14:57:53,14,101992,21720,cap-wifi3,-56,309700000,433300000,6640,7008,00:05:06,00:00:00
|
||||
1788526675,14:57:55,14:57:55,14,152504,61272,cap-wifi3,-59,309700000,433300000,6160,6512,00:05:08,00:00:00
|
||||
1788526677,14:57:57,14:57:57,22,130520,26552,cap-wifi3,-57,309700000,433300000,6160,6512,00:05:10,00:00:00
|
||||
1788526679,14:57:59,14:57:59,17,155408,24688,cap-wifi3,-57,309700000,433300000,6160,6512,00:05:12,00:00:00
|
||||
1788526681,14:58:01,14:58:01,9,244456,41424,cap-wifi3,-58,309700000,433300000,6160,6512,00:05:14,00:00:00
|
||||
1788526683,14:58:03,14:58:03,10,115640,26032,cap-wifi3,-59,309700000,433300000,5600,5920,00:05:16,00:00:00
|
||||
1788526685,14:58:05,14:58:05,10,154824,24456,cap-wifi3,-59,309700000,433300000,5600,5920,00:05:18,00:00:00
|
||||
1788526687,14:58:07,14:58:08,9,135144,25000,cap-wifi3,-59,309700000,487500000,5600,5920,00:05:20,00:00:00
|
||||
1788526689,14:58:09,14:58:10,20,122800,29936,cap-wifi3,-58,309700000,455800000,5600,5920,00:05:22,00:00:00
|
||||
1788526691,14:58:11,14:58:12,10,152160,65768,cap-wifi3,-58,309700000,455800000,6160,6512,00:05:24,00:00:00
|
||||
1788526692,14:58:12,RECONNECT
|
||||
|
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-iphone.csv (Takt 2s, Client F2:62:4C:E1:AF:09)
|
||||
@@ -0,0 +1,42 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788526611,14:56:51,14:56:51,38,120880,24032,cap-wifi6,-85,68800000,17200000,166280,4310536,01:04:25,00:00:00
|
||||
1788526613,14:56:53,14:56:53,9,151312,62480,cap-wifi6,-85,103200000,17200000,550344,592824,01:04:27,00:00:00
|
||||
1788526615,14:56:55,14:56:55,10,127416,44832,cap-wifi6,-86,68800000,25800000,413184,340240,01:04:29,00:00:00
|
||||
1788526617,14:56:57,14:56:57,6,127712,21960,cap-wifi6,-86,68800000,25800000,413184,340240,01:04:31,00:00:00
|
||||
1788526619,14:56:59,14:56:59,13,157888,29816,cap-wifi6,-85,103200000,34400000,1524128,1126592,01:04:33,00:00:00
|
||||
1788526621,14:57:01,14:57:01,7,322208,124400,cap-wifi6,-86,68800000,34400000,1886112,547568,01:04:35,00:00:00
|
||||
1788526623,14:57:03,14:57:03,13,451416,4332552,cap-wifi6,-86,68800000,34400000,1886112,547568,01:04:37,00:00:00
|
||||
1788526625,14:57:05,14:57:05,10,398720,136640,cap-wifi6,-85,68800000,17200000,1079440,2625392,01:04:39,00:00:00
|
||||
1788526627,14:57:07,14:57:07,12,947800,446984,cap-wifi6,-86,68800000,17200000,1108088,760040,01:04:42,00:00:00
|
||||
1788526629,14:57:09,14:57:09,20,7610296,3321592,cap-wifi6,-86,68800000,17200000,1108088,760040,01:04:44,00:00:00
|
||||
1788526631,14:57:11,14:57:11,8,2720136,2091232,cap-wifi6,-82,68800000,51600000,1684720,1013032,01:04:46,00:00:00
|
||||
1788526633,14:57:13,14:57:13,9,2261568,2680088,cap-wifi6,-87,103200000,25800000,324776,3447064,01:04:48,00:00:00
|
||||
1788526636,14:57:16,14:57:15,7,108584,42016,cap-wifi6,-87,103200000,25800000,324776,3447064,01:04:50,00:00:00
|
||||
1788526637,14:57:17,14:57:17,4,1478952,581848,cap-wifi6,-85,103200000,17200000,598680,602896,01:04:52,00:00:00
|
||||
1788526639,14:57:19,14:57:19,14,229272,54576,cap-wifi6,-84,103200000,34400000,1017664,775360,01:04:54,00:00:00
|
||||
1788526641,14:57:21,14:57:21,6,100688,29040,cap-wifi6,-84,103200000,34400000,1017664,775360,01:04:56,00:00:00
|
||||
1788526644,14:57:24,14:57:23,14,472232,195392,cap-wifi6,-86,68800000,17200000,14752,6688,01:04:58,00:00:00
|
||||
1788526645,14:57:25,14:57:25,19,229864,36304,cap-wifi6,-86,68800000,17200000,1094984,789880,01:05:00,00:00:00
|
||||
1788526647,14:57:27,14:57:28,9,132384,26968,cap-wifi6,-86,68800000,17200000,1094984,789880,01:05:02,00:00:00
|
||||
1788526649,14:57:29,14:57:30,18,196672,48240,cap-wifi6,-84,68800000,51600000,912296,563704,01:05:04,00:00:00
|
||||
1788526652,14:57:32,14:57:32,15,237176,31328,cap-wifi6,-87,68800000,11000000,2448600,1495240,01:05:06,00:00:00
|
||||
1788526654,14:57:34,14:57:34,9,147328,27456,cap-wifi6,-87,68800000,17200000,1326824,729536,01:05:08,00:00:00
|
||||
1788526656,14:57:36,14:57:36,11,122784,22816,cap-wifi6,-87,68800000,17200000,1326824,729536,01:05:10,00:00:00
|
||||
1788526658,14:57:38,14:57:38,9,122248,26192,cap-wifi6,-83,68800000,51600000,1292552,729408,01:05:12,00:00:00
|
||||
1788526660,14:57:40,14:57:40,14,167632,49032,cap-wifi6,-87,103200000,17200000,2131488,1138888,01:05:14,00:00:00
|
||||
1788526662,14:57:42,14:57:42,11,89248,17856,cap-wifi6,-87,103200000,17200000,2131488,1138888,01:05:16,00:00:00
|
||||
1788526664,14:57:44,14:57:44,7,125232,33536,cap-wifi6,-86,103200000,17200000,1495112,774112,01:05:18,00:00:00
|
||||
1788526666,14:57:46,14:57:46,8,1056872,260048,cap-wifi6,-86,103200000,17200000,773656,584032,01:05:20,00:00:00
|
||||
1788526668,14:57:48,14:57:48,11,172776,252208,cap-wifi6,-86,103200000,17200000,773656,584032,01:05:22,00:00:00
|
||||
1788526670,14:57:50,14:57:50,14,116656,22744,cap-wifi6,-87,51600000,17200000,256424,250360,01:05:24,00:00:00
|
||||
1788526672,14:57:52,14:57:52,8,234376,122480,cap-wifi6,-83,51600000,51600000,771864,575120,01:05:26,00:00:00
|
||||
1788526674,14:57:54,14:57:54,14,101992,21720,cap-wifi6,-83,51600000,51600000,771864,575120,01:05:28,00:00:00
|
||||
1788526676,14:57:56,14:57:56,9,152504,61272,cap-wifi6,-84,68800000,17200000,944720,547864,01:05:31,00:00:00
|
||||
1788526678,14:57:58,14:57:58,15,130520,26552,cap-wifi6,-88,51600000,17200000,1086104,614336,01:05:33,00:00:00
|
||||
1788526680,14:58:00,14:58:00,16,155408,24688,cap-wifi6,-88,51600000,17200000,1086104,614336,01:05:35,00:00:00
|
||||
1788526682,14:58:02,14:58:02,10,244456,41424,cap-wifi6,-85,68800000,17200000,1515776,563200,01:05:37,00:00:00
|
||||
1788526684,14:58:04,14:58:04,8,183848,56872,cap-wifi6,-84,103200000,25800000,888888,696272,01:05:39,00:00:00
|
||||
1788526686,14:58:06,14:58:06,9,305320,47576,cap-wifi6,-84,103200000,25800000,888888,696272,01:05:41,00:00:00
|
||||
1788526688,14:58:08,14:58:08,14,331408,59856,cap-wifi6,-84,68800000,34400000,860480,583048,01:05:43,00:00:00
|
||||
1788526690,14:58:10,14:58:10,17,322448,65576,cap-wifi6,-87,51600000,25800000,1068352,553088,01:05:45,00:00:00
|
||||
1788526692,14:58:12,RECONNECT
|
||||
|
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-macbook.csv (Takt 2s, Client 56:71:6C:22:E6:A9)
|
||||
@@ -0,0 +1,42 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788526611,14:56:51,14:56:51,38,120880,24032,cap-wifi5,-51,137600000,229400000,0,0,01:04:22,00:00:09
|
||||
1788526613,14:56:53,14:56:53,9,151312,62480,cap-wifi5,-51,137600000,258100000,1680,1776,01:04:24,00:00:00
|
||||
1788526615,14:56:55,14:56:55,10,127416,44832,cap-wifi5,-53,137600000,229400000,2800,2960,01:04:26,00:00:00
|
||||
1788526617,14:56:57,14:56:57,6,127712,21960,cap-wifi5,-53,137600000,229400000,2800,2960,01:04:28,00:00:00
|
||||
1788526619,14:56:59,14:56:59,13,157888,29816,cap-wifi5,-50,137600000,229400000,2800,2960,01:04:30,00:00:00
|
||||
1788526621,14:57:01,14:57:01,7,322208,124400,cap-wifi5,-51,137600000,229400000,3248,3328,01:04:32,00:00:00
|
||||
1788526623,14:57:03,14:57:03,13,451416,4332552,cap-wifi5,-51,137600000,229400000,3248,3328,01:04:34,00:00:00
|
||||
1788526625,14:57:05,14:57:05,10,398720,136640,cap-wifi5,-51,137600000,229400000,2800,2960,01:04:36,00:00:00
|
||||
1788526627,14:57:07,14:57:07,12,947800,446984,cap-wifi5,-51,137600000,229400000,2800,2960,01:04:38,00:00:00
|
||||
1788526629,14:57:09,14:57:09,20,7610296,3321592,cap-wifi5,-51,137600000,229400000,2800,2960,01:04:40,00:00:00
|
||||
1788526631,14:57:11,14:57:11,8,2720136,2091232,cap-wifi5,-52,137600000,229400000,3360,3552,01:04:42,00:00:00
|
||||
1788526633,14:57:13,14:57:13,9,2261568,2680088,cap-wifi5,-52,137600000,229400000,3360,3552,01:04:44,00:00:00
|
||||
1788526636,14:57:16,14:57:15,7,108584,42016,cap-wifi5,-52,137600000,229400000,3360,3552,01:04:46,00:00:00
|
||||
1788526637,14:57:17,14:57:17,4,1478952,581848,cap-wifi5,-53,137600000,258100000,2800,2960,01:04:48,00:00:00
|
||||
1788526639,14:57:19,14:57:19,14,229272,54576,cap-wifi5,-53,137600000,229400000,4184,4968,01:04:50,00:00:00
|
||||
1788526641,14:57:21,14:57:21,6,100688,29040,cap-wifi5,-53,137600000,229400000,4184,4968,01:04:52,00:00:00
|
||||
1788526644,14:57:24,14:57:23,14,472232,195392,cap-wifi5,-61,137600000,229400000,2800,2960,01:04:54,00:00:00
|
||||
1788526645,14:57:25,14:57:25,19,229864,36304,cap-wifi5,-59,172100000,229400000,2800,2960,01:04:56,00:00:00
|
||||
1788526647,14:57:27,14:57:28,9,132384,26968,cap-wifi5,-59,172100000,229400000,2800,2960,01:04:58,00:00:00
|
||||
1788526649,14:57:29,14:57:30,18,196672,48240,cap-wifi5,-60,172100000,229400000,2800,2368,01:05:00,00:00:00
|
||||
1788526652,14:57:32,14:57:32,15,237176,31328,cap-wifi5,-60,172100000,229400000,3360,3552,01:05:02,00:00:00
|
||||
1788526654,14:57:34,14:57:34,9,147328,27456,cap-wifi5,-60,172100000,229400000,2800,2960,01:05:04,00:00:00
|
||||
1788526656,14:57:36,14:57:36,11,122784,22816,cap-wifi5,-60,172100000,229400000,2800,2960,01:05:07,00:00:00
|
||||
1788526658,14:57:38,14:57:38,9,122248,26192,cap-wifi5,-59,129000000,258100000,3856,2960,01:05:09,00:00:00
|
||||
1788526660,14:57:40,14:57:40,14,167632,49032,cap-wifi5,-58,114700000,229400000,7888,15664,01:05:11,00:00:00
|
||||
1788526662,14:57:42,14:57:42,11,89248,17856,cap-wifi5,-58,114700000,229400000,7888,15664,01:05:13,00:00:00
|
||||
1788526664,14:57:44,14:57:44,7,125232,33536,cap-wifi5,-57,114700000,206500000,3360,2960,01:05:15,00:00:00
|
||||
1788526666,14:57:46,14:57:46,8,1056872,260048,cap-wifi5,-57,114700000,206500000,2800,2960,01:05:17,00:00:00
|
||||
1788526668,14:57:48,14:57:48,11,172776,252208,cap-wifi5,-57,114700000,206500000,2800,2960,01:05:19,00:00:00
|
||||
1788526670,14:57:50,14:57:50,14,116656,22744,cap-wifi5,-57,154900000,172100000,3360,3552,01:05:21,00:00:00
|
||||
1788526672,14:57:52,14:57:52,8,234376,122480,cap-wifi5,-58,154900000,206500000,2800,2960,01:05:23,00:00:00
|
||||
1788526674,14:57:54,14:57:54,14,101992,21720,cap-wifi5,-58,154900000,206500000,2800,2960,01:05:25,00:00:00
|
||||
1788526676,14:57:56,14:57:56,9,152504,61272,cap-wifi5,-58,154900000,229400000,2800,2960,01:05:27,00:00:00
|
||||
1788526678,14:57:58,14:57:58,15,130520,26552,cap-wifi5,-58,103200000,229400000,2800,2960,01:05:29,00:00:00
|
||||
1788526680,14:58:00,14:58:00,16,155408,24688,cap-wifi5,-58,103200000,229400000,2800,2960,01:05:31,00:00:00
|
||||
1788526682,14:58:02,14:58:02,10,244456,41424,cap-wifi5,-58,103200000,206500000,3248,3328,01:05:33,00:00:00
|
||||
1788526684,14:58:04,14:58:04,8,183848,56872,cap-wifi5,-58,103200000,206500000,2800,2960,01:05:35,00:00:00
|
||||
1788526686,14:58:06,14:58:06,9,305320,47576,cap-wifi5,-58,103200000,206500000,2800,2960,01:05:37,00:00:00
|
||||
1788526688,14:58:08,14:58:08,14,331408,59856,cap-wifi5,-59,103200000,229400000,2800,2960,01:05:39,00:00:00
|
||||
1788526690,14:58:10,14:58:10,17,322448,65576,cap-wifi5,-58,103200000,206500000,2800,2960,01:05:41,00:00:00
|
||||
1788526692,14:58:12,RECONNECT
|
||||
|
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-s22.csv (Takt 2s, Client 2A:0D:B0:5D:AD:A7)
|
||||
2397
docs/messdaten/tp25-runde-dauerping/archiv-150553/walk-ping-ipad.csv
Normal file
2397
docs/messdaten/tp25-runde-dauerping/archiv-150553/walk-ping-ipad.csv
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2398
docs/messdaten/tp25-runde-dauerping/archiv-150553/walk-ping-s22.csv
Normal file
2398
docs/messdaten/tp25-runde-dauerping/archiv-150553/walk-ping-s22.csv
Normal file
File diff suppressed because it is too large
Load Diff
4
docs/messdaten/tp25-runde-dauerping/geraete.txt
Normal file
4
docs/messdaten/tp25-runde-dauerping/geraete.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
iphone|10.40.10.196|F2:62:4C:E1:AF:09
|
||||
s22|10.40.10.179|2A:0D:B0:5D:AD:A7
|
||||
ipad|10.40.10.180|CA:B8:D4:3F:8A:81
|
||||
macbook|10.40.10.82|56:71:6C:22:E6:A9
|
||||
0
docs/messdaten/tp25-runde-dauerping/konsole.log
Normal file
0
docs/messdaten/tp25-runde-dauerping/konsole.log
Normal file
6
docs/messdaten/tp25-runde-dauerping/markers.csv
Normal file
6
docs/messdaten/tp25-runde-dauerping/markers.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
ts_epoch,ts_local,marker
|
||||
1788527256,15:07:36,PINM=off
|
||||
1788527283,15:08:03,PINM=off
|
||||
1788527311,15:08:31,PINM=off
|
||||
1788527320,15:08:40,PINM=off
|
||||
1788527414,15:10:14,STOP
|
||||
|
1
docs/messdaten/tp25-runde-dauerping/phase.json
Normal file
1
docs/messdaten/tp25-runde-dauerping/phase.json
Normal file
@@ -0,0 +1 @@
|
||||
{"mode": "langzeit", "phase": "GEHWEG", "title": "Roaming-Messung l\u00e4uft", "instruction": "Aufzeichnung gestoppt.", "step": 0, "steps": 0, "ends": 0}
|
||||
131
docs/messdaten/tp25-runde-dauerping/sampler-ipad.csv
Normal file
131
docs/messdaten/tp25-runde-dauerping/sampler-ipad.csv
Normal file
@@ -0,0 +1,131 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788527155,15:05:55,15:05:55,26,110192,66624,cap-wifi3,-58,6000000,216700000,0,0,00:07:03,00:00:00
|
||||
1788527157,15:05:57,15:05:57,10,248200,181784,cap-wifi3,-58,6000000,216700000,0,0,00:07:05,00:00:00
|
||||
1788527159,15:05:59,15:05:59,27,895392,176224,cap-wifi3,-54,309700000,455800000,100936,106200,00:07:07,00:00:00
|
||||
1788527161,15:06:01,15:06:01,5,271768,3546664,cap-wifi3,-55,309700000,309700000,4800,18208,00:07:09,00:00:00
|
||||
1788527163,15:06:03,15:06:03,7,212384,57592,cap-wifi3,-55,309700000,309700000,4800,18208,00:07:11,00:00:00
|
||||
1788527165,15:06:05,15:06:05,6,119880,34152,cap-wifi3,-52,309700000,455800000,62952,10824,00:07:13,00:00:00
|
||||
1788527167,15:06:07,15:06:07,6,285512,62760,cap-wifi3,-48,309700000,412900000,2800,2960,00:07:15,00:00:00
|
||||
1788527169,15:06:09,15:06:09,18,135200,33432,cap-wifi3,-48,309700000,412900000,2800,2960,00:07:17,00:00:00
|
||||
1788527171,15:06:11,15:06:11,2,80168,35552,cap-wifi3,-50,309700000,433300000,2800,3360,00:07:19,00:00:00
|
||||
1788527173,15:06:13,15:06:13,6,263824,45616,cap-wifi3,-49,309700000,455800000,2800,2960,00:07:21,00:00:00
|
||||
1788527175,15:06:15,15:06:15,4,139448,79056,cap-wifi3,-49,309700000,455800000,2800,2960,00:07:23,00:00:00
|
||||
1788527177,15:06:17,15:06:17,7,125944,34792,cap-wifi3,-51,309700000,487500000,2800,2960,00:07:25,00:00:00
|
||||
1788527179,15:06:19,15:06:19,21,228896,34848,cap-wifi3,-51,309700000,516200000,3360,3552,00:07:27,00:00:00
|
||||
1788527181,15:06:21,15:06:21,6,91344,100616,cap-wifi3,-51,309700000,516200000,3360,3552,00:07:29,00:00:00
|
||||
1788527183,15:06:23,15:06:23,8,1161368,460544,cap-wifi3,-52,309700000,541700000,2800,3520,00:07:31,00:00:00
|
||||
1788527185,15:06:25,15:06:25,9,669424,189984,cap-wifi3,-51,309700000,433300000,2800,2960,00:07:33,00:00:00
|
||||
1788527187,15:06:27,15:06:27,8,220472,72928,cap-wifi3,-51,309700000,433300000,2800,2960,00:07:35,00:00:00
|
||||
1788527189,15:06:29,15:06:29,19,85696,19672,cap-wifi3,-50,309700000,455800000,11872,3328,00:07:37,00:00:00
|
||||
1788527191,15:06:31,15:06:31,7,88056,17368,cap-wifi3,-52,309700000,516200000,3360,3552,00:07:39,00:00:00
|
||||
1788527193,15:06:33,15:06:33,7,78232,15688,cap-wifi3,-52,309700000,516200000,3360,3552,00:07:41,00:00:00
|
||||
1788527195,15:06:35,15:06:35,7,77824,19488,cap-wifi3,-50,309700000,433300000,2800,2960,00:07:43,00:00:00
|
||||
1788527197,15:06:37,15:06:37,11,91648,29960,cap-wifi3,-56,309700000,455800000,2800,2960,00:07:45,00:00:00
|
||||
1788527199,15:06:39,15:06:39,19,479584,403096,cap-wifi3,-54,309700000,325000000,2800,2960,00:07:47,00:00:00
|
||||
1788527201,15:06:41,15:06:41,6,83504,18032,cap-wifi3,-54,309700000,325000000,2800,2960,00:07:49,00:00:00
|
||||
1788527203,15:06:43,15:06:43,8,94312,27480,cap-wifi3,-53,309700000,344100000,3248,2960,00:07:51,00:00:00
|
||||
1788527205,15:06:45,15:06:45,7,139816,113728,cap-wifi3,-52,309700000,390000000,2800,2960,00:07:53,00:00:00
|
||||
1788527207,15:06:47,15:06:47,8,77512,23304,cap-wifi3,-52,309700000,390000000,2800,2960,00:07:55,00:00:00
|
||||
1788527209,15:06:49,15:06:49,22,135424,86176,cap-wifi3,-53,309700000,412900000,2800,3360,00:07:57,00:00:00
|
||||
1788527211,15:06:51,15:06:52,6,80072,20128,cap-wifi3,-52,309700000,433300000,2800,2960,00:07:59,00:00:00
|
||||
1788527213,15:06:53,15:06:54,7,81544,23592,cap-wifi3,-52,309700000,433300000,2800,2960,00:08:01,00:00:00
|
||||
1788527216,15:06:56,15:06:56,8,118248,77704,cap-wifi3,-52,309700000,455800000,3808,3552,00:08:03,00:00:00
|
||||
1788527218,15:06:58,15:06:58,6,115296,40584,cap-wifi3,-54,309700000,487500000,2800,2960,00:08:05,00:00:00
|
||||
1788527220,15:07:00,15:07:00,36,72144,17920,cap-wifi3,-54,309700000,487500000,2800,2960,00:08:07,00:00:00
|
||||
1788527222,15:07:02,15:07:02,6,87272,19464,cap-wifi3,-53,309700000,516200000,3808,3920,00:08:09,00:00:00
|
||||
1788527224,15:07:04,15:07:04,7,341584,177744,cap-wifi3,-54,309700000,487500000,3488,2960,00:08:11,00:00:00
|
||||
1788527226,15:07:06,15:07:06,5,96008,29072,cap-wifi3,-54,309700000,487500000,3488,2960,00:08:14,00:00:00
|
||||
1788527228,15:07:08,15:07:08,9,88184,20760,cap-wifi3,-54,309700000,516200000,2800,2960,00:08:16,00:00:00
|
||||
1788527230,15:07:10,15:07:10,19,245616,37632,cap-wifi3,-54,309700000,541700000,3424,2960,00:08:18,00:00:00
|
||||
1788527232,15:07:12,15:07:12,7,136904,41680,cap-wifi3,-54,309700000,541700000,3424,2960,00:08:20,00:00:00
|
||||
1788527234,15:07:14,15:07:14,5,176432,193240,cap-wifi3,-54,309700000,573500000,3360,2960,00:08:22,00:00:00
|
||||
1788527236,15:07:16,15:07:16,5,668616,412672,cap-wifi3,-52,309700000,573500000,2800,2960,00:08:24,00:00:00
|
||||
1788527238,15:07:18,15:07:18,12,10040200,401976,cap-wifi3,-52,309700000,573500000,2800,2960,00:08:26,00:00:00
|
||||
1788527240,15:07:20,15:07:20,21,6694840,181608,cap-wifi3,-52,309700000,573500000,2800,2960,00:08:28,00:00:00
|
||||
1788527242,15:07:22,15:07:22,8,269904,95904,cap-wifi3,-52,309700000,573500000,2800,2960,00:08:30,00:00:00
|
||||
1788527244,15:07:24,15:07:24,10,97040,38768,cap-wifi3,-52,309700000,573500000,2800,2960,00:08:32,00:00:00
|
||||
1788527246,15:07:26,15:07:26,8,265536,57040,cap-wifi3,-51,309700000,573500000,2800,2960,00:08:34,00:00:00
|
||||
1788527248,15:07:28,15:07:28,8,79496,17712,cap-wifi3,-52,309700000,573500000,3360,8208,00:08:36,00:00:00
|
||||
1788527250,15:07:30,15:07:30,5,82824,26656,cap-wifi3,-52,309700000,573500000,3360,8208,00:08:38,00:00:00
|
||||
1788527252,15:07:32,15:07:32,8,79440,24984,cap-wifi3,-52,309700000,573500000,3360,7808,00:08:40,00:00:00
|
||||
1788527254,15:07:34,15:07:34,7,84240,17432,cap-wifi3,-52,309700000,573500000,5248,2960,00:08:42,00:00:00
|
||||
1788527256,15:07:36,15:07:36,15,74928,18888,cap-wifi3,-52,309700000,573500000,5248,2960,00:08:44,00:00:00
|
||||
1788527258,15:07:38,15:07:38,6,79856,17376,cap-wifi3,-51,309700000,573500000,3328,3520,00:08:46,00:00:00
|
||||
1788527260,15:07:40,15:07:40,5,91680,31720,cap-wifi3,-52,275300000,573500000,2800,2960,00:08:48,00:00:00
|
||||
1788527262,15:07:42,15:07:42,6,82760,21192,cap-wifi3,-52,275300000,573500000,2800,2960,00:08:50,00:00:00
|
||||
1788527264,15:07:44,15:07:44,7,91960,31680,cap-wifi3,-51,275300000,573500000,2800,2960,00:08:52,00:00:00
|
||||
1788527266,15:07:46,15:07:46,6,986832,256184,cap-wifi3,-51,275300000,573500000,3920,4144,00:08:54,00:00:00
|
||||
1788527268,15:07:48,15:07:48,7,204344,305984,cap-wifi3,-51,275300000,573500000,3920,4144,00:08:56,00:00:00
|
||||
1788527270,15:07:50,15:07:50,9,90376,25984,cap-wifi3,-52,258100000,573500000,2240,2368,00:08:58,00:00:00
|
||||
1788527272,15:07:52,15:07:52,5,106024,28632,cap-wifi3,-52,258100000,286800000,2800,2960,00:09:00,00:00:00
|
||||
1788527274,15:07:54,15:07:54,8,90816,27368,cap-wifi3,-52,258100000,286800000,2800,2960,00:09:02,00:00:00
|
||||
1788527276,15:07:56,15:07:56,9,80656,22520,cap-wifi3,-52,258100000,573500000,2800,2960,00:09:04,00:00:00
|
||||
1788527278,15:07:58,15:07:58,8,74792,15952,cap-wifi3,-54,258100000,412900000,2800,2960,00:09:06,00:00:00
|
||||
1788527280,15:08:00,15:08:00,9,97280,32008,cap-wifi3,-54,258100000,412900000,2800,2960,00:09:08,00:00:00
|
||||
1788527282,15:08:02,15:08:02,22,405584,131400,cap-wifi3,-55,258100000,412900000,2800,2960,00:09:10,00:00:00
|
||||
1788527284,15:08:04,15:08:04,15,99616,29344,cap-wifi3,-53,258100000,433300000,2800,2960,00:09:12,00:00:00
|
||||
1788527286,15:08:06,15:08:06,3,116040,34784,cap-wifi3,-53,258100000,433300000,2800,2960,00:09:14,00:00:00
|
||||
1788527288,15:08:08,15:08:08,6,263752,46256,cap-wifi3,-54,258100000,455800000,2800,3360,00:09:16,00:00:00
|
||||
1788527290,15:08:10,15:08:10,5,154688,74104,cap-wifi3,-54,258100000,487500000,2800,2960,00:09:18,00:00:00
|
||||
1788527292,15:08:12,15:08:13,4,437800,144600,cap-wifi3,-54,258100000,487500000,2800,2960,00:09:20,00:00:00
|
||||
1788527294,15:08:14,15:08:15,5,273784,69248,cap-wifi3,-56,258100000,390000000,3808,3552,00:09:22,00:00:00
|
||||
1788527297,15:08:17,15:08:17,4,110840,33232,cap-wifi3,-56,258100000,433300000,2800,2960,00:09:24,00:00:00
|
||||
1788527299,15:08:19,15:08:19,5,80584,34112,cap-wifi3,-55,258100000,455800000,3360,3552,00:09:26,00:00:00
|
||||
1788527301,15:08:21,15:08:21,5,89992,25208,cap-wifi3,-55,258100000,455800000,3360,3552,00:09:28,00:00:00
|
||||
1788527303,15:08:23,15:08:23,5,258520,122376,cap-wifi3,-56,258100000,433300000,2800,2960,00:09:30,00:00:00
|
||||
1788527305,15:08:25,15:08:25,8,484544,159104,cap-wifi3,-55,258100000,455800000,2800,2960,00:09:33,00:00:00
|
||||
1788527307,15:08:27,15:08:27,5,85832,21400,cap-wifi3,-55,258100000,455800000,2800,2960,00:09:35,00:00:00
|
||||
1788527309,15:08:29,15:08:29,7,86968,23984,cap-wifi3,-56,258100000,433300000,2800,2960,00:09:37,00:00:00
|
||||
1788527311,15:08:31,15:08:31,4,92848,27216,cap-wifi3,-57,258100000,455800000,2800,2960,00:09:39,00:00:00
|
||||
1788527313,15:08:33,15:08:33,13,88112,30272,cap-wifi3,-57,258100000,455800000,2800,2960,00:09:41,00:00:00
|
||||
1788527315,15:08:35,15:08:35,6,97568,38688,cap-wifi3,-57,258100000,433300000,2800,2960,00:09:43,00:00:00
|
||||
1788527317,15:08:37,15:08:37,7,69376,15424,cap-wifi3,-58,258100000,455800000,3360,3552,00:09:45,00:00:00
|
||||
1788527319,15:08:39,15:08:39,22,95672,27872,cap-wifi3,-58,258100000,455800000,3360,3552,00:09:47,00:00:00
|
||||
1788527321,15:08:41,15:08:41,20,81008,14064,cap-wifi3,-58,258100000,433300000,2800,2960,00:09:49,00:00:00
|
||||
1788527323,15:08:43,15:08:43,9,79480,19824,cap-wifi3,-59,258100000,325000000,3328,2960,00:09:51,00:00:00
|
||||
1788527325,15:08:45,15:08:45,11,83080,28888,cap-wifi3,-59,258100000,325000000,3328,2960,00:09:53,00:00:00
|
||||
1788527327,15:08:47,15:08:47,7,77224,19568,cap-wifi3,-59,258100000,390000000,3360,3952,00:09:55,00:00:00
|
||||
1788527329,15:08:49,15:08:49,20,87976,23544,cap-wifi3,-58,258100000,412900000,2800,2960,00:09:57,00:00:00
|
||||
1788527331,15:08:51,15:08:51,6,99288,43960,cap-wifi3,-58,258100000,412900000,2800,2960,00:09:59,00:00:00
|
||||
1788527333,15:08:53,15:08:53,4,78784,16504,cap-wifi3,-58,258100000,390000000,3808,3552,00:10:01,00:00:00
|
||||
1788527335,15:08:55,15:08:55,8,100664,43024,cap-wifi3,-52,6000000,412900000,3360,3552,00:10:03,00:00:00
|
||||
1788527337,15:08:57,15:08:57,6,75392,68792,cap-wifi3,-52,6000000,412900000,3360,3552,00:10:05,00:00:00
|
||||
1788527339,15:08:59,15:08:59,18,84648,23296,cap-wifi3,-52,258100000,433300000,2800,3360,00:10:07,00:00:00
|
||||
1788527341,15:09:01,15:09:01,5,146608,49608,cap-wifi3,-53,258100000,455800000,2800,2960,00:10:09,00:00:00
|
||||
1788527343,15:09:03,15:09:03,6,271512,52760,cap-wifi3,-53,258100000,455800000,2800,2960,00:10:11,00:00:00
|
||||
1788527345,15:09:05,15:09:05,6,400696,3660640,cap-wifi3,-56,258100000,433300000,2800,2960,00:10:13,00:00:00
|
||||
1788527347,15:09:07,15:09:07,6,131696,25096,cap-wifi3,-55,258100000,390000000,2800,2960,00:10:15,00:00:00
|
||||
1788527349,15:09:09,15:09:09,19,213416,92736,cap-wifi3,-55,258100000,390000000,2800,2960,00:10:17,00:00:00
|
||||
1788527351,15:09:11,15:09:11,6,319104,63216,cap-wifi3,-52,6000000,309700000,2800,2960,00:10:19,00:00:00
|
||||
1788527353,15:09:13,15:09:13,8,153896,48144,cap-wifi3,-54,258100000,344100000,3360,3552,00:10:21,00:00:00
|
||||
1788527355,15:09:15,15:09:15,5,190952,58360,cap-wifi3,-54,258100000,344100000,3360,3552,00:10:23,00:00:00
|
||||
1788527357,15:09:17,15:09:17,7,232928,149512,cap-wifi3,-55,258100000,390000000,4080,6912,00:10:25,00:00:00
|
||||
1788527359,15:09:19,15:09:20,19,108000,26560,cap-wifi3,-56,258100000,412900000,3360,3552,00:10:27,00:00:00
|
||||
1788527361,15:09:21,15:09:22,10,2754208,213840,cap-wifi3,-56,258100000,412900000,3360,3552,00:10:29,00:00:00
|
||||
1788527364,15:09:24,15:09:24,7,314040,73608,cap-wifi3,-55,258100000,216700000,15040,7600,00:10:31,00:00:00
|
||||
1788527366,15:09:26,15:09:26,5,485488,100744,cap-wifi3,-54,258100000,229400000,3304,6992,00:10:33,00:00:00
|
||||
1788527368,15:09:28,15:09:28,6,123816,28072,cap-wifi3,-54,258100000,229400000,3304,6992,00:10:35,00:00:00
|
||||
1788527370,15:09:30,15:09:30,19,124944,35616,cap-wifi3,-56,258100000,433300000,2800,2960,00:10:37,00:00:00
|
||||
1788527372,15:09:32,15:09:32,5,171352,44496,cap-wifi3,-54,258100000,433300000,4928,0,00:10:39,00:00:00
|
||||
1788527374,15:09:34,15:09:34,6,166240,43784,cap-wifi3,-54,6000000,433300000,2800,0,00:10:42,00:00:00
|
||||
1788527376,15:09:36,15:09:36,6,150760,49464,cap-wifi3,-54,6000000,433300000,2800,0,00:10:44,00:00:00
|
||||
1788527378,15:09:38,15:09:38,10,185768,47120,cap-wifi3,-55,258100000,433300000,2800,6496,00:10:46,00:00:00
|
||||
1788527380,15:09:40,15:09:40,18,190032,49512,cap-wifi3,-54,258100000,433300000,2240,0,00:10:48,00:00:00
|
||||
1788527382,15:09:42,15:09:42,8,97808,22304,cap-wifi3,-54,258100000,433300000,2240,0,00:10:50,00:00:00
|
||||
1788527384,15:09:44,15:09:44,8,148400,53672,cap-wifi3,-54,6000000,433300000,13464,368,00:10:52,00:00:00
|
||||
1788527386,15:09:46,15:09:46,2,97568,37160,cap-wifi3,-54,258100000,455800000,2800,2960,00:10:54,00:00:00
|
||||
1788527388,15:09:48,15:09:48,4,76456,19280,cap-wifi3,-54,258100000,455800000,2800,2960,00:10:56,00:00:00
|
||||
1788527390,15:09:50,15:09:50,9,74488,14496,cap-wifi3,-54,258100000,390000000,2928,0,00:10:58,00:00:00
|
||||
1788527392,15:09:52,15:09:52,9,81688,114120,cap-wifi3,-54,258100000,390000000,2240,0,00:11:00,00:00:00
|
||||
1788527394,15:09:54,15:09:54,11,139472,94312,cap-wifi3,-54,258100000,390000000,2240,0,00:11:02,00:00:00
|
||||
1788527396,15:09:56,15:09:56,8,99376,34800,cap-wifi3,-54,258100000,390000000,2240,0,00:11:04,00:00:00
|
||||
1788527398,15:09:58,15:09:58,7,95624,20936,cap-wifi3,-54,258100000,390000000,2800,0,00:11:06,00:00:00
|
||||
1788527400,15:10:00,15:10:00,11,75688,17080,cap-wifi3,-54,258100000,390000000,2800,0,00:11:08,00:00:00
|
||||
1788527402,15:10:02,15:10:02,8,194448,59984,cap-wifi3,-54,258100000,390000000,2240,0,00:11:10,00:00:00
|
||||
1788527404,15:10:04,15:10:04,5,87848,23392,cap-wifi3,-54,258100000,390000000,5040,0,00:11:12,00:00:00
|
||||
1788527406,15:10:06,15:10:06,4,102440,31824,cap-wifi3,-54,258100000,390000000,5040,0,00:11:14,00:00:00
|
||||
1788527408,15:10:08,15:10:08,7,140352,49312,cap-wifi3,-54,258100000,390000000,2800,0,00:11:16,00:00:00
|
||||
1788527410,15:10:10,15:10:10,20,81216,18128,cap-wifi3,-53,258100000,390000000,2688,0,00:11:18,00:00:00
|
||||
1788527412,15:10:12,15:10:12,8,223088,23248,cap-wifi3,-53,258100000,390000000,2688,0,00:11:20,00:00:00
|
||||
1788527414,15:10:14,15:10:14,7,139784,51840,cap-wifi3,-54,258100000,390000000,2240,0,00:11:22,00:00:00
|
||||
1788527415,15:10:15,RECONNECT
|
||||
|
1
docs/messdaten/tp25-runde-dauerping/sampler-ipad.out
Normal file
1
docs/messdaten/tp25-runde-dauerping/sampler-ipad.out
Normal file
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-ipad.csv (Takt 2s, Client CA:B8:D4:3F:8A:81)
|
||||
@@ -0,0 +1,2 @@
|
||||
14:58:12 Verbindung weg -- neuer Versuch in 2 s
|
||||
15:10:15 Verbindung weg -- neuer Versuch in 2 s
|
||||
130
docs/messdaten/tp25-runde-dauerping/sampler-iphone.csv
Normal file
130
docs/messdaten/tp25-runde-dauerping/sampler-iphone.csv
Normal file
@@ -0,0 +1,130 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788527155,15:05:55,RECONNECT
|
||||
1788527159,15:05:59,15:05:59,26,895392,176224,cap-wifi3,-63,154900000,309700000,15624,7104,00:13:12,00:00:00
|
||||
1788527161,15:06:01,15:06:01,12,271768,3546664,cap-wifi3,-61,154900000,325000000,4576,3552,00:13:14,00:00:00
|
||||
1788527163,15:06:03,15:06:03,11,212384,57592,cap-wifi3,-61,154900000,325000000,4576,3552,00:13:16,00:00:00
|
||||
1788527165,15:06:05,15:06:05,6,119880,34152,cap-wifi3,-59,154900000,325000000,2240,0,00:13:18,00:00:00
|
||||
1788527167,15:06:07,15:06:07,6,285512,62760,cap-wifi3,-58,154900000,325000000,3360,0,00:13:20,00:00:00
|
||||
1788527169,15:06:09,15:06:09,18,135200,33432,cap-wifi3,-58,154900000,325000000,3360,0,00:13:22,00:00:00
|
||||
1788527171,15:06:11,15:06:11,2,80168,35552,cap-wifi3,-58,154900000,325000000,2240,0,00:13:24,00:00:00
|
||||
1788527173,15:06:13,15:06:13,6,263824,45616,cap-wifi3,-57,154900000,325000000,3360,0,00:13:26,00:00:00
|
||||
1788527175,15:06:15,15:06:15,4,139448,79056,cap-wifi3,-57,154900000,325000000,3360,0,00:13:28,00:00:00
|
||||
1788527177,15:06:17,15:06:17,7,125944,34792,cap-wifi3,-58,154900000,325000000,1680,0,00:13:30,00:00:00
|
||||
1788527179,15:06:19,15:06:19,21,228896,34848,cap-wifi3,-60,154900000,325000000,0,0,00:13:32,00:00:00
|
||||
1788527181,15:06:21,15:06:21,6,91344,100616,cap-wifi3,-60,154900000,325000000,0,0,00:13:34,00:00:00
|
||||
1788527183,15:06:23,15:06:23,8,1161368,460544,cap-wifi3,-62,154900000,325000000,4368,4592,00:13:36,00:00:00
|
||||
1788527185,15:06:25,15:06:25,9,669424,189984,cap-wifi3,-56,154900000,344100000,2800,3712,00:13:38,00:00:00
|
||||
1788527187,15:06:27,15:06:27,8,220472,72928,cap-wifi3,-56,154900000,344100000,2800,3712,00:13:40,00:00:00
|
||||
1788527189,15:06:29,15:06:29,19,85696,19672,cap-wifi3,-60,154900000,325000000,4880,10808,00:13:42,00:00:00
|
||||
1788527191,15:06:31,15:06:31,7,80008,30360,cap-wifi3,-48,154900000,309700000,4080,4992,00:13:44,00:00:00
|
||||
1788527193,15:06:33,15:06:33,7,85392,35808,cap-wifi3,-48,154900000,309700000,4080,4992,00:13:46,00:00:00
|
||||
1788527195,15:06:35,15:06:35,7,81000,33304,cap-wifi3,-52,154900000,325000000,2800,2960,00:13:48,00:00:00
|
||||
1788527197,15:06:37,15:06:37,11,80840,16392,cap-wifi3,-60,154900000,344100000,2800,2960,00:13:50,00:00:00
|
||||
1788527199,15:06:39,15:06:39,19,479584,403096,cap-wifi3,-60,154900000,344100000,2800,2960,00:13:52,00:00:00
|
||||
1788527201,15:06:41,15:06:41,6,83504,18032,cap-wifi3,-54,154900000,390000000,2800,2960,00:13:54,00:00:00
|
||||
1788527203,15:06:43,15:06:43,8,94312,27480,cap-wifi3,-52,154900000,412900000,3776,3552,00:13:56,00:00:00
|
||||
1788527205,15:06:45,15:06:45,7,139816,113728,cap-wifi3,-54,154900000,455800000,3360,3552,00:13:58,00:00:00
|
||||
1788527207,15:06:47,15:06:47,8,77512,23304,cap-wifi3,-54,154900000,455800000,3360,3552,00:14:00,00:00:00
|
||||
1788527209,15:06:49,15:06:49,22,135424,86176,cap-wifi3,-53,206500000,455800000,2800,2960,00:14:02,00:00:00
|
||||
1788527211,15:06:51,15:06:51,6,80072,20128,cap-wifi3,-53,12000000,516200000,2800,2960,00:14:04,00:00:00
|
||||
1788527213,15:06:53,15:06:53,7,81544,23592,cap-wifi3,-53,12000000,516200000,2800,2960,00:14:06,00:00:00
|
||||
1788527215,15:06:55,15:06:55,8,118248,77704,cap-wifi3,-54,206500000,573500000,3248,3552,00:14:08,00:00:00
|
||||
1788527217,15:06:57,15:06:58,6,115296,40584,cap-wifi3,-53,206500000,573500000,3360,3552,00:14:10,00:00:00
|
||||
1788527219,15:06:59,15:07:00,36,72144,17920,cap-wifi3,-53,206500000,573500000,3360,3552,00:14:12,00:00:00
|
||||
1788527221,15:07:01,15:07:02,6,87272,19464,cap-wifi3,-55,206500000,412900000,2800,2960,00:14:14,00:00:00
|
||||
1788527224,15:07:04,15:07:04,7,341584,177744,cap-wifi3,-55,206500000,455800000,2800,2960,00:14:16,00:00:00
|
||||
1788527226,15:07:06,15:07:06,5,96008,29072,cap-wifi3,-55,206500000,455800000,2800,2960,00:14:18,00:00:00
|
||||
1788527228,15:07:08,15:07:08,9,88184,20760,cap-wifi3,-54,206500000,455800000,2800,2960,00:14:21,00:00:00
|
||||
1788527230,15:07:10,15:07:10,19,245616,37632,cap-wifi3,-55,206500000,433300000,2800,2960,00:14:23,00:00:00
|
||||
1788527232,15:07:12,15:07:12,7,136904,41680,cap-wifi3,-55,206500000,433300000,2800,2960,00:14:25,00:00:00
|
||||
1788527234,15:07:14,15:07:14,5,176432,193240,cap-wifi3,-54,206500000,455800000,2800,2960,00:14:27,00:00:00
|
||||
1788527236,15:07:16,15:07:16,5,668616,412672,cap-wifi3,-53,206500000,487500000,3360,3552,00:14:29,00:00:00
|
||||
1788527238,15:07:18,15:07:18,12,10040200,401976,cap-wifi3,-53,206500000,487500000,3360,3552,00:14:31,00:00:00
|
||||
1788527240,15:07:20,15:07:20,21,6694840,181608,cap-wifi3,-53,6000000,516200000,2800,3336,00:14:33,00:00:00
|
||||
1788527242,15:07:22,15:07:22,7,269904,95904,cap-wifi3,-53,206500000,487500000,2800,2960,00:14:35,00:00:00
|
||||
1788527244,15:07:24,15:07:24,6,97040,38768,cap-wifi3,-53,206500000,487500000,2800,2960,00:14:37,00:00:00
|
||||
1788527246,15:07:26,15:07:26,6,265536,57040,cap-wifi3,-53,206500000,516200000,3360,3552,00:14:39,00:00:00
|
||||
1788527248,15:07:28,15:07:28,8,79496,17712,cap-wifi3,-52,206500000,487500000,2800,2960,00:14:41,00:00:00
|
||||
1788527250,15:07:30,15:07:30,20,82824,26656,cap-wifi3,-52,206500000,487500000,2800,2960,00:14:43,00:00:00
|
||||
1788527252,15:07:32,15:07:32,8,79440,24984,cap-wifi3,-53,206500000,516200000,2800,2960,00:14:45,00:00:00
|
||||
1788527254,15:07:34,15:07:34,7,84240,17432,cap-wifi3,-51,206500000,541700000,4560,3552,00:14:47,00:00:00
|
||||
1788527256,15:07:36,15:07:36,15,74928,18888,cap-wifi3,-51,206500000,541700000,4560,3552,00:14:49,00:00:00
|
||||
1788527258,15:07:38,15:07:38,6,79856,17376,cap-wifi3,-51,206500000,573500000,2800,2960,00:14:51,00:00:00
|
||||
1788527260,15:07:40,15:07:40,5,91680,31720,cap-wifi3,-51,206500000,573500000,2800,2960,00:14:53,00:00:00
|
||||
1788527262,15:07:42,15:07:42,6,82760,21192,cap-wifi3,-51,206500000,573500000,2800,2960,00:14:55,00:00:00
|
||||
1788527264,15:07:44,15:07:44,7,91960,31680,cap-wifi3,-51,206500000,573500000,2800,2960,00:14:57,00:00:00
|
||||
1788527266,15:07:46,15:07:46,6,986832,256184,cap-wifi3,-51,206500000,573500000,2800,2960,00:14:59,00:00:00
|
||||
1788527268,15:07:48,15:07:48,7,204344,305984,cap-wifi3,-51,206500000,573500000,2800,2960,00:15:01,00:00:00
|
||||
1788527270,15:07:50,15:07:50,9,90376,25984,cap-wifi3,-51,206500000,516200000,3248,3328,00:15:03,00:00:00
|
||||
1788527272,15:07:52,15:07:52,5,106024,28632,cap-wifi3,-50,12000000,516200000,3808,3920,00:15:05,00:00:00
|
||||
1788527274,15:07:54,15:07:54,8,86752,24568,cap-wifi3,-50,12000000,516200000,3808,3920,00:15:07,00:00:00
|
||||
1788527276,15:07:56,15:07:56,9,68568,17040,cap-wifi3,-51,206500000,541700000,2800,2960,00:15:09,00:00:00
|
||||
1788527278,15:07:58,15:07:58,8,104792,53200,cap-wifi3,-51,206500000,390000000,3360,3552,00:15:11,00:00:00
|
||||
1788527280,15:08:00,15:08:00,9,304368,102592,cap-wifi3,-51,206500000,390000000,3360,3552,00:15:13,00:00:00
|
||||
1788527282,15:08:02,15:08:02,22,74432,14824,cap-wifi3,-50,24000000,412900000,2800,2960,00:15:15,00:00:00
|
||||
1788527284,15:08:04,15:08:04,15,99616,29344,cap-wifi3,-51,154900000,433300000,3360,3552,00:15:17,00:00:00
|
||||
1788527286,15:08:06,15:08:06,3,116040,34784,cap-wifi3,-51,154900000,433300000,3360,3552,00:15:19,00:00:00
|
||||
1788527288,15:08:08,15:08:08,6,263752,46256,cap-wifi3,-50,24000000,455800000,2800,2960,00:15:21,00:00:00
|
||||
1788527290,15:08:10,15:08:10,5,154688,74104,cap-wifi3,-51,154900000,487500000,2800,2960,00:15:23,00:00:00
|
||||
1788527292,15:08:12,15:08:12,4,437800,144600,cap-wifi3,-51,154900000,487500000,2800,2960,00:15:25,00:00:00
|
||||
1788527294,15:08:14,15:08:14,5,273784,69248,cap-wifi3,-50,154900000,516200000,3248,3552,00:15:27,00:00:00
|
||||
1788527296,15:08:16,15:08:16,4,110840,33232,cap-wifi3,-50,154900000,541700000,2800,2960,00:15:29,00:00:00
|
||||
1788527298,15:08:18,15:08:18,5,80584,34112,cap-wifi3,-50,154900000,541700000,2800,2960,00:15:31,00:00:00
|
||||
1788527300,15:08:20,15:08:20,5,89992,25208,cap-wifi3,-51,206500000,573500000,3360,3928,00:15:33,00:00:00
|
||||
1788527302,15:08:22,15:08:23,5,258520,122376,cap-wifi3,-50,206500000,573500000,2800,2960,00:15:35,00:00:00
|
||||
1788527304,15:08:24,15:08:25,8,484544,159104,cap-wifi3,-50,206500000,573500000,2800,2960,00:15:37,00:00:00
|
||||
1788527306,15:08:26,15:08:27,5,85832,21400,cap-wifi3,-52,206500000,573500000,6336,6536,00:15:39,00:00:00
|
||||
1788527309,15:08:29,15:08:29,7,86968,23984,cap-wifi3,-51,206500000,573500000,4384,5704,00:15:41,00:00:00
|
||||
1788527311,15:08:31,15:08:31,4,92848,27216,cap-wifi3,-50,24000000,573500000,3360,2960,00:15:44,00:00:00
|
||||
1788527313,15:08:33,15:08:33,13,88112,30272,cap-wifi3,-50,24000000,573500000,3360,2960,00:15:46,00:00:00
|
||||
1788527315,15:08:35,15:08:35,6,97568,38688,cap-wifi3,-51,172100000,573500000,2800,2960,00:15:48,00:00:00
|
||||
1788527317,15:08:37,15:08:37,7,69376,15424,cap-wifi3,-51,172100000,573500000,2800,2960,00:15:50,00:00:00
|
||||
1788527319,15:08:39,15:08:39,7,95672,27872,cap-wifi3,-51,172100000,573500000,2800,2960,00:15:52,00:00:00
|
||||
1788527321,15:08:41,15:08:41,8,81008,14064,cap-wifi3,-52,172100000,573500000,5648,5744,00:15:54,00:00:00
|
||||
1788527323,15:08:43,15:08:43,8,79480,19824,cap-wifi3,-51,172100000,573500000,3360,3552,00:15:56,00:00:00
|
||||
1788527325,15:08:45,15:08:45,6,83080,28888,cap-wifi3,-51,172100000,573500000,3360,3552,00:15:58,00:00:00
|
||||
1788527327,15:08:47,15:08:47,9,77224,19568,cap-wifi3,-52,172100000,573500000,2800,2960,00:16:00,00:00:00
|
||||
1788527329,15:08:49,15:08:49,7,87976,23544,cap-wifi3,-53,172100000,573500000,2800,2960,00:16:02,00:00:00
|
||||
1788527331,15:08:51,15:08:51,6,99288,43960,cap-wifi3,-53,172100000,573500000,2800,2960,00:16:04,00:00:00
|
||||
1788527333,15:08:53,15:08:53,4,78784,16504,cap-wifi3,-56,172100000,455800000,4416,4840,00:16:06,00:00:00
|
||||
1788527335,15:08:55,15:08:55,8,100664,43024,cap-wifi3,-56,154900000,344100000,3408,3656,00:16:08,00:00:00
|
||||
1788527337,15:08:57,15:08:57,6,75392,68792,cap-wifi3,-56,154900000,344100000,3408,3656,00:16:10,00:00:00
|
||||
1788527339,15:08:59,15:08:59,18,84648,23296,cap-wifi3,-53,154900000,344100000,3936,4496,00:16:12,00:00:00
|
||||
1788527341,15:09:01,15:09:01,5,146608,49608,cap-wifi3,-53,154900000,325000000,3408,3656,00:16:14,00:00:00
|
||||
1788527343,15:09:03,15:09:03,6,271512,52760,cap-wifi3,-53,154900000,325000000,3408,3656,00:16:16,00:00:00
|
||||
1788527345,15:09:05,15:09:05,6,400696,3660640,cap-wifi3,-51,154900000,344100000,3408,2960,00:16:18,00:00:00
|
||||
1788527347,15:09:07,15:09:07,6,131696,25096,cap-wifi3,-58,154900000,325000000,4896,5048,00:16:20,00:00:00
|
||||
1788527349,15:09:09,15:09:09,19,213416,92736,cap-wifi3,-58,154900000,325000000,4896,5048,00:16:22,00:00:00
|
||||
1788527351,15:09:11,15:09:11,6,319104,63216,cap-wifi3,-50,206500000,344100000,3408,3656,00:16:24,00:00:00
|
||||
1788527353,15:09:13,15:09:13,8,153896,48144,cap-wifi3,-46,206500000,412900000,3968,4248,00:16:26,00:00:00
|
||||
1788527355,15:09:15,15:09:15,5,190952,58360,cap-wifi3,-46,206500000,412900000,3968,4248,00:16:28,00:00:00
|
||||
1788527357,15:09:17,15:09:17,7,232928,149512,cap-wifi3,-59,206500000,433300000,3408,3656,00:16:30,00:00:00
|
||||
1788527359,15:09:19,15:09:19,19,108000,26560,cap-wifi3,-60,206500000,344100000,3856,4032,00:16:32,00:00:00
|
||||
1788527361,15:09:21,15:09:21,10,2754208,213840,cap-wifi3,-60,206500000,344100000,3856,4032,00:16:34,00:00:00
|
||||
1788527363,15:09:23,15:09:24,7,314040,73608,cap-wifi3,-60,206500000,325000000,5488,11504,00:16:36,00:00:00
|
||||
1788527365,15:09:25,15:09:26,5,485488,100744,cap-wifi3,-60,206500000,344100000,4736,5096,00:16:38,00:00:00
|
||||
1788527367,15:09:28,15:09:28,6,123816,28072,cap-wifi3,-60,206500000,344100000,4736,5096,00:16:40,00:00:00
|
||||
1788527370,15:09:30,15:09:30,19,124944,35616,cap-wifi3,-61,154900000,292500000,2800,0,00:16:42,00:00:00
|
||||
1788527372,15:09:32,15:09:32,5,171352,44496,cap-wifi3,-60,137600000,325000000,3136,368,00:16:44,00:00:00
|
||||
1788527374,15:09:34,15:09:34,6,166240,43784,cap-wifi3,-60,137600000,325000000,3136,368,00:16:47,00:00:00
|
||||
1788527376,15:09:36,15:09:36,6,150760,49464,cap-wifi3,-55,172100000,309700000,15056,42256,00:16:49,00:00:00
|
||||
1788527378,15:09:38,15:09:38,10,185768,47120,cap-wifi3,-62,172100000,325000000,3408,3656,00:16:51,00:00:00
|
||||
1788527380,15:09:40,15:09:40,18,190032,49512,cap-wifi3,-62,172100000,344100000,3408,3656,00:16:53,00:00:00
|
||||
1788527382,15:09:42,15:09:42,8,97808,22304,cap-wifi3,-62,172100000,344100000,3408,3656,00:16:55,00:00:00
|
||||
1788527384,15:09:44,15:09:44,8,148400,53672,cap-wifi3,-63,12000000,412900000,3856,10808,00:16:57,00:00:00
|
||||
1788527386,15:09:46,15:09:46,2,97568,37160,cap-wifi3,-62,172100000,412900000,2800,2960,00:16:59,00:00:00
|
||||
1788527388,15:09:48,15:09:48,4,76456,19280,cap-wifi3,-62,172100000,412900000,2800,2960,00:17:01,00:00:00
|
||||
1788527390,15:09:50,15:09:50,17,74488,14496,cap-wifi3,-64,172100000,325000000,7688,7440,00:17:03,00:00:00
|
||||
1788527392,15:09:52,15:09:52,4,81688,114120,cap-wifi3,-62,172100000,344100000,3888,4768,00:17:05,00:00:00
|
||||
1788527394,15:09:54,15:09:54,8,139472,94312,cap-wifi3,-62,172100000,344100000,3888,4768,00:17:07,00:00:00
|
||||
1788527396,15:09:56,15:09:56,4,99376,34800,cap-wifi3,-63,172100000,412900000,3328,3424,00:17:09,00:00:00
|
||||
1788527398,15:09:58,15:09:58,5,95624,20936,cap-wifi3,-62,172100000,412900000,3360,3552,00:17:11,00:00:00
|
||||
1788527400,15:10:00,15:10:00,11,75688,17080,cap-wifi3,-62,172100000,412900000,3360,3552,00:17:13,00:00:00
|
||||
1788527402,15:10:02,15:10:02,8,194448,59984,cap-wifi3,-61,172100000,390000000,2800,0,00:17:15,00:00:00
|
||||
1788527404,15:10:04,15:10:04,5,87848,23392,cap-wifi3,-60,172100000,390000000,2128,368,00:17:17,00:00:00
|
||||
1788527406,15:10:06,15:10:06,4,102440,31824,cap-wifi3,-60,172100000,390000000,2128,368,00:17:19,00:00:00
|
||||
1788527408,15:10:08,15:10:08,7,140352,49312,cap-wifi3,-61,172100000,390000000,2240,0,00:17:21,00:00:00
|
||||
1788527410,15:10:10,15:10:10,20,88352,30376,cap-wifi3,-61,137600000,390000000,3248,0,00:17:23,00:00:00
|
||||
1788527412,15:10:12,15:10:12,8,124328,46808,cap-wifi3,-61,137600000,390000000,3248,0,00:17:25,00:00:00
|
||||
1788527414,15:10:14,15:10:14,7,84784,23040,cap-wifi3,-61,137600000,390000000,2800,0,00:17:27,00:00:00
|
||||
1788527415,15:10:15,RECONNECT
|
||||
|
1
docs/messdaten/tp25-runde-dauerping/sampler-iphone.out
Normal file
1
docs/messdaten/tp25-runde-dauerping/sampler-iphone.out
Normal file
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-iphone.csv (Takt 2s, Client F2:62:4C:E1:AF:09)
|
||||
@@ -0,0 +1,9 @@
|
||||
14:58:12 Verbindung weg -- neuer Versuch in 2 s
|
||||
ssh_askpass: exec(/usr/X11R6/bin/ssh-askpass): No such file or directory
|
||||
Permission denied, please try again.
|
||||
ssh_askpass: exec(/usr/X11R6/bin/ssh-askpass): No such file or directory
|
||||
Permission denied, please try again.
|
||||
ssh_askpass: exec(/usr/X11R6/bin/ssh-askpass): No such file or directory
|
||||
admin@10.40.99.1: Permission denied (publickey,password).
|
||||
15:05:55 Verbindung weg -- neuer Versuch in 2 s
|
||||
15:10:15 Verbindung weg -- neuer Versuch in 2 s
|
||||
130
docs/messdaten/tp25-runde-dauerping/sampler-macbook.csv
Normal file
130
docs/messdaten/tp25-runde-dauerping/sampler-macbook.csv
Normal file
@@ -0,0 +1,130 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788527155,15:05:55,15:05:55,26,215104,164208,cap-wifi3,-59,344100000,455800000,1108432,1179376,00:06:21,00:00:00
|
||||
1788527157,15:05:57,15:05:57,10,230144,103104,cap-wifi3,-58,412900000,455800000,376304,298808,00:06:23,00:00:00
|
||||
1788527159,15:05:59,15:05:59,27,997352,175928,cap-wifi3,-58,412900000,455800000,376304,298808,00:06:25,00:00:00
|
||||
1788527161,15:06:01,15:06:01,5,496624,179032,cap-wifi3,-60,455800000,455800000,2283840,1594024,00:06:27,00:00:00
|
||||
1788527163,15:06:03,15:06:03,7,112272,25664,cap-wifi3,-61,455800000,344100000,71224,20160,00:06:30,00:00:00
|
||||
1788527165,15:06:05,15:06:06,6,353280,101384,cap-wifi3,-61,455800000,344100000,71224,20160,00:06:32,00:00:00
|
||||
1788527167,15:06:08,15:06:08,6,137256,37360,cap-wifi3,-63,344100000,344100000,1205496,674488,00:06:34,00:00:00
|
||||
1788527170,15:06:10,15:06:10,18,373144,1851168,cap-wifi3,-62,344100000,455800000,625632,2151904,00:06:36,00:00:00
|
||||
1788527172,15:06:12,15:06:12,2,79504,15688,cap-wifi3,-62,344100000,455800000,625632,2151904,00:06:38,00:00:00
|
||||
1788527174,15:06:14,15:06:14,6,215576,3512448,cap-wifi3,-61,412900000,412900000,720568,420128,00:06:40,00:00:00
|
||||
1788527176,15:06:16,15:06:16,4,170440,37144,cap-wifi3,-63,344100000,309700000,1040816,801272,00:06:42,00:00:00
|
||||
1788527178,15:06:18,15:06:18,7,187488,1860720,cap-wifi3,-63,344100000,309700000,1040816,801272,00:06:44,00:00:00
|
||||
1788527180,15:06:20,15:06:20,21,418584,3563696,cap-wifi3,-63,412900000,275300000,496424,2170904,00:06:46,00:00:00
|
||||
1788527182,15:06:22,15:06:22,6,91920,32648,cap-wifi3,-64,412900000,275300000,539264,491728,00:06:48,00:00:00
|
||||
1788527184,15:06:24,15:06:24,8,229720,340576,cap-wifi3,-64,412900000,275300000,539264,491728,00:06:50,00:00:00
|
||||
1788527186,15:06:26,15:06:26,11,324680,63616,cap-wifi3,-63,412900000,344100000,768576,455936,00:06:52,00:00:00
|
||||
1788527188,15:06:28,15:06:28,7,323944,57120,cap-wifi3,-67,344100000,309700000,515712,335688,00:06:54,00:00:00
|
||||
1788527190,15:06:30,15:06:30,7,89536,26840,cap-wifi3,-67,344100000,309700000,515712,335688,00:06:56,00:00:00
|
||||
1788527192,15:06:32,15:06:32,6,88056,17368,cap-wifi3,-62,344100000,344100000,546008,422232,00:06:58,00:00:00
|
||||
1788527194,15:06:34,15:06:34,6,78232,15688,cap-wifi3,-62,412900000,344100000,403184,296104,00:07:00,00:00:00
|
||||
1788527196,15:06:36,15:06:36,6,77824,19488,cap-wifi3,-62,412900000,344100000,403184,296104,00:07:02,00:00:00
|
||||
1788527198,15:06:38,15:06:38,8,91648,29960,cap-wifi3,-62,412900000,344100000,665616,416832,00:07:04,00:00:00
|
||||
1788527200,15:06:40,15:06:40,6,479584,403096,cap-wifi3,-63,344100000,275300000,1141120,678936,00:07:06,00:00:00
|
||||
1788527202,15:06:42,15:06:42,5,83504,18032,cap-wifi3,-63,344100000,275300000,1141120,678936,00:07:08,00:00:00
|
||||
1788527204,15:06:44,15:06:44,12,94312,27480,cap-wifi3,-64,344100000,344100000,511368,235632,00:07:10,00:00:00
|
||||
1788527206,15:06:46,15:06:46,11,104592,25288,cap-wifi3,-65,412900000,309700000,882160,555064,00:07:12,00:00:00
|
||||
1788527208,15:06:48,15:06:48,9,77672,15824,cap-wifi3,-65,344100000,275300000,71864,300800,00:07:14,00:00:00
|
||||
1788527210,15:06:50,15:06:50,8,130536,65520,cap-wifi3,-65,344100000,275300000,71864,300800,00:07:16,00:00:00
|
||||
1788527212,15:06:52,15:06:52,6,179704,71320,cap-wifi3,-65,309700000,344100000,612752,430056,00:07:19,00:00:00
|
||||
1788527214,15:06:54,15:06:54,7,150376,135320,cap-wifi3,-64,309700000,309700000,556768,426072,00:07:21,00:00:00
|
||||
1788527216,15:06:56,15:06:57,7,180576,117008,cap-wifi3,-64,309700000,309700000,556768,426072,00:07:23,00:00:00
|
||||
1788527219,15:06:59,15:06:59,9,81080,17128,cap-wifi3,-65,344100000,412900000,687448,312096,00:07:25,00:00:00
|
||||
1788527221,15:07:01,15:07:01,6,267072,71760,cap-wifi3,-64,412900000,309700000,1456168,436368,00:07:27,00:00:00
|
||||
1788527223,15:07:03,15:07:03,7,229720,79648,cap-wifi3,-64,412900000,309700000,1456168,436368,00:07:29,00:00:00
|
||||
1788527225,15:07:05,15:07:05,12,613656,242376,cap-wifi3,-65,412900000,344100000,643504,429016,00:07:31,00:00:00
|
||||
1788527227,15:07:07,15:07:07,9,136256,40080,cap-wifi3,-64,412900000,344100000,619904,419664,00:07:33,00:00:00
|
||||
1788527229,15:07:09,15:07:09,11,113040,49536,cap-wifi3,-64,412900000,344100000,619904,419664,00:07:35,00:00:00
|
||||
1788527231,15:07:11,15:07:11,7,85432,17976,cap-wifi3,-64,412900000,309700000,1090376,738848,00:07:37,00:00:00
|
||||
1788527233,15:07:13,15:07:13,5,81944,26128,cap-wifi3,-65,412900000,344100000,947112,611480,00:07:39,00:00:00
|
||||
1788527235,15:07:15,15:07:15,5,954264,397144,cap-wifi3,-65,412900000,344100000,947112,611480,00:07:41,00:00:00
|
||||
1788527237,15:07:17,15:07:17,12,3430312,274976,cap-wifi3,-64,412900000,344100000,1132848,732040,00:07:43,00:00:00
|
||||
1788527239,15:07:19,15:07:19,21,5774264,240088,cap-wifi3,-63,412900000,344100000,886256,615784,00:07:45,00:00:00
|
||||
1788527241,15:07:21,15:07:21,7,419688,124632,cap-wifi3,-63,412900000,344100000,886256,615784,00:07:47,00:00:00
|
||||
1788527243,15:07:23,15:07:23,6,146872,47152,cap-wifi3,-64,412900000,344100000,588616,494568,00:07:49,00:00:00
|
||||
1788527245,15:07:25,15:07:25,6,469520,144920,cap-wifi3,-62,412900000,344100000,576512,462856,00:07:51,00:00:00
|
||||
1788527247,15:07:27,15:07:27,8,87480,21512,cap-wifi3,-62,412900000,344100000,576512,462856,00:07:53,00:00:00
|
||||
1788527249,15:07:29,15:07:29,20,89592,20496,cap-wifi3,-63,455800000,344100000,256840,24640,00:07:55,00:00:00
|
||||
1788527251,15:07:31,15:07:31,9,77304,18144,cap-wifi3,-63,455800000,309700000,883728,710608,00:07:57,00:00:00
|
||||
1788527253,15:07:33,15:07:33,7,84240,17432,cap-wifi3,-63,455800000,309700000,883728,710608,00:07:59,00:00:00
|
||||
1788527255,15:07:35,15:07:35,9,74928,18888,cap-wifi3,-62,455800000,412900000,33632,15216,00:08:01,00:00:00
|
||||
1788527257,15:07:37,15:07:37,12,79856,17376,cap-wifi3,-63,455800000,412900000,859640,23024,00:08:03,00:00:00
|
||||
1788527259,15:07:39,15:07:39,19,91680,31720,cap-wifi3,-62,455800000,412900000,1005448,689888,00:08:06,00:00:00
|
||||
1788527261,15:07:41,15:07:41,7,82760,21192,cap-wifi3,-62,455800000,412900000,1005448,689888,00:08:08,00:00:00
|
||||
1788527263,15:07:43,15:07:44,6,91960,31680,cap-wifi3,-63,516200000,412900000,393768,296624,00:08:10,00:00:00
|
||||
1788527266,15:07:46,15:07:46,12,986832,256184,cap-wifi3,-63,516200000,412900000,558880,414936,00:08:12,00:00:00
|
||||
1788527268,15:07:48,15:07:48,8,204344,305984,cap-wifi3,-63,516200000,412900000,558880,414936,00:08:14,00:00:00
|
||||
1788527270,15:07:50,15:07:50,21,90376,25984,cap-wifi3,-63,455800000,344100000,423096,346496,00:08:16,00:00:00
|
||||
1788527272,15:07:52,15:07:52,9,106024,28632,cap-wifi3,-63,455800000,412900000,549712,433200,00:08:18,00:00:00
|
||||
1788527274,15:07:54,15:07:54,8,86752,24568,cap-wifi3,-63,455800000,412900000,549712,433200,00:08:20,00:00:00
|
||||
1788527276,15:07:56,15:07:56,8,68568,17040,cap-wifi3,-63,455800000,344100000,391568,303576,00:08:22,00:00:00
|
||||
1788527278,15:07:58,15:07:58,7,104792,53200,cap-wifi3,-62,455800000,344100000,715856,336320,00:08:24,00:00:00
|
||||
1788527280,15:08:00,15:08:00,17,304368,102592,cap-wifi3,-62,455800000,344100000,715856,336320,00:08:26,00:00:00
|
||||
1788527282,15:08:02,15:08:02,10,74432,14824,cap-wifi3,-62,455800000,344100000,1540504,579064,00:08:28,00:00:00
|
||||
1788527284,15:08:04,15:08:04,15,84656,54904,cap-wifi3,-62,455800000,412900000,241664,55784,00:08:30,00:00:00
|
||||
1788527286,15:08:06,15:08:06,3,157752,48776,cap-wifi3,-62,455800000,412900000,241664,55784,00:08:32,00:00:00
|
||||
1788527288,15:08:08,15:08:08,6,93880,28544,cap-wifi3,-61,455800000,344100000,662200,323008,00:08:34,00:00:00
|
||||
1788527290,15:08:10,15:08:10,5,92704,21680,cap-wifi3,-62,455800000,412900000,1547016,993208,00:08:36,00:00:00
|
||||
1788527292,15:08:12,15:08:12,4,1096952,456376,cap-wifi3,-62,455800000,412900000,1547016,993208,00:08:38,00:00:00
|
||||
1788527294,15:08:14,15:08:14,5,96296,34168,cap-wifi3,-62,455800000,412900000,658464,380200,00:08:40,00:00:00
|
||||
1788527296,15:08:16,15:08:16,4,323536,108008,cap-wifi3,-62,516200000,412900000,1653400,1083248,00:08:42,00:00:00
|
||||
1788527298,15:08:18,15:08:18,5,106776,31872,cap-wifi3,-62,516200000,412900000,1653400,1083248,00:08:44,00:00:00
|
||||
1788527300,15:08:20,15:08:20,5,180440,70648,cap-wifi3,-62,516200000,412900000,601784,323352,00:08:46,00:00:00
|
||||
1788527302,15:08:22,15:08:22,5,258520,122376,cap-wifi3,-63,516200000,344100000,1414784,982048,00:08:48,00:00:00
|
||||
1788527304,15:08:24,15:08:24,8,484544,159104,cap-wifi3,-63,516200000,344100000,1414784,982048,00:08:50,00:00:00
|
||||
1788527306,15:08:26,15:08:26,5,85832,21400,cap-wifi3,-62,516200000,412900000,594728,332184,00:08:52,00:00:00
|
||||
1788527308,15:08:28,15:08:28,7,86968,23984,cap-wifi3,-62,455800000,412900000,1676496,1014016,00:08:54,00:00:00
|
||||
1788527310,15:08:30,15:08:30,4,92848,27216,cap-wifi3,-62,455800000,412900000,1676496,1014016,00:08:57,00:00:00
|
||||
1788527312,15:08:32,15:08:32,13,88112,30272,cap-wifi3,-61,455800000,412900000,862336,707464,00:08:59,00:00:00
|
||||
1788527314,15:08:34,15:08:35,6,97568,38688,cap-wifi3,-62,455800000,412900000,802192,493640,00:09:01,00:00:00
|
||||
1788527317,15:08:37,15:08:37,7,69376,15424,cap-wifi3,-63,455800000,412900000,410264,299608,00:09:03,00:00:00
|
||||
1788527319,15:08:39,15:08:39,7,95672,27872,cap-wifi3,-63,455800000,412900000,410264,299608,00:09:05,00:00:00
|
||||
1788527321,15:08:41,15:08:41,8,81008,14064,cap-wifi3,-62,516200000,412900000,1058008,922664,00:09:07,00:00:00
|
||||
1788527323,15:08:43,15:08:43,8,79480,19824,cap-wifi3,-62,516200000,412900000,396520,170800,00:09:09,00:00:00
|
||||
1788527325,15:08:45,15:08:45,6,83080,28888,cap-wifi3,-62,516200000,412900000,396520,170800,00:09:11,00:00:00
|
||||
1788527327,15:08:47,15:08:47,9,77224,19568,cap-wifi3,-62,516200000,455800000,899408,689584,00:09:13,00:00:00
|
||||
1788527329,15:08:49,15:08:49,7,87976,23544,cap-wifi3,-62,516200000,412900000,44600,15184,00:09:15,00:00:00
|
||||
1788527331,15:08:51,15:08:51,6,99288,43960,cap-wifi3,-62,516200000,412900000,44600,15184,00:09:17,00:00:00
|
||||
1788527333,15:08:53,15:08:53,4,78784,16504,cap-wifi3,-62,516200000,344100000,903552,691192,00:09:19,00:00:00
|
||||
1788527335,15:08:55,15:08:55,8,100664,43024,cap-wifi3,-64,412900000,309700000,69328,39008,00:09:21,00:00:00
|
||||
1788527337,15:08:57,15:08:57,6,75392,68792,cap-wifi3,-64,412900000,309700000,69328,39008,00:09:23,00:00:00
|
||||
1788527339,15:08:59,15:08:59,18,84648,23296,cap-wifi3,-63,344100000,309700000,1149696,710336,00:09:25,00:00:00
|
||||
1788527341,15:09:01,15:09:01,5,146608,49608,cap-wifi3,-62,412900000,344100000,2232624,903848,00:09:27,00:00:00
|
||||
1788527343,15:09:03,15:09:03,6,271512,52760,cap-wifi3,-62,412900000,344100000,2232624,903848,00:09:29,00:00:00
|
||||
1788527345,15:09:05,15:09:05,6,400696,3660640,cap-wifi3,-61,344100000,412900000,756464,448360,00:09:31,00:00:00
|
||||
1788527347,15:09:07,15:09:07,6,131696,25096,cap-wifi3,-63,344100000,344100000,1392608,910264,00:09:33,00:00:00
|
||||
1788527349,15:09:09,15:09:09,19,213416,92736,cap-wifi3,-63,344100000,344100000,1392608,910264,00:09:35,00:00:00
|
||||
1788527351,15:09:11,15:09:11,6,319104,63216,cap-wifi3,-62,412900000,309700000,1209392,477456,00:09:37,00:00:00
|
||||
1788527353,15:09:13,15:09:13,8,153896,48144,cap-wifi3,-62,412900000,344100000,1506680,898696,00:09:39,00:00:00
|
||||
1788527355,15:09:15,15:09:15,5,190952,58360,cap-wifi3,-62,412900000,344100000,1506680,898696,00:09:41,00:00:00
|
||||
1788527357,15:09:17,15:09:17,7,232928,149512,cap-wifi3,-64,412900000,344100000,1033704,613072,00:09:44,00:00:00
|
||||
1788527359,15:09:19,15:09:19,19,108000,26560,cap-wifi3,-64,309700000,344100000,1108648,735944,00:09:46,00:00:00
|
||||
1788527361,15:09:21,15:09:22,10,2754208,213840,cap-wifi3,-64,309700000,344100000,1108648,735944,00:09:48,00:00:00
|
||||
1788527363,15:09:23,15:09:24,7,314040,73608,cap-wifi3,-63,344100000,275300000,981328,613912,00:09:50,00:00:00
|
||||
1788527366,15:09:26,15:09:26,5,485488,100744,cap-wifi3,-58,309700000,309700000,1262008,690008,00:09:52,00:00:00
|
||||
1788527368,15:09:28,15:09:28,6,123816,28072,cap-wifi3,-58,309700000,309700000,1262008,690008,00:09:54,00:00:00
|
||||
1788527370,15:09:30,15:09:30,19,124944,35616,cap-wifi3,-63,309700000,206500000,260104,31680,00:09:56,00:00:00
|
||||
1788527372,15:09:32,15:09:32,5,171352,44496,cap-wifi3,-61,344100000,309700000,1238528,574776,00:09:58,00:00:00
|
||||
1788527374,15:09:34,15:09:34,6,166240,43784,cap-wifi3,-64,344100000,344100000,531000,227904,00:10:00,00:00:00
|
||||
1788527376,15:09:36,15:09:36,6,150760,49464,cap-wifi3,-64,344100000,344100000,531000,227904,00:10:02,00:00:00
|
||||
1788527378,15:09:38,15:09:38,10,185768,47120,cap-wifi3,-64,344100000,309700000,929200,634112,00:10:04,00:00:00
|
||||
1788527380,15:09:40,15:09:40,18,190032,49512,cap-wifi3,-64,344100000,309700000,666528,183736,00:10:06,00:00:00
|
||||
1788527382,15:09:42,15:09:42,8,97808,22304,cap-wifi3,-64,344100000,309700000,666528,183736,00:10:08,00:00:00
|
||||
1788527384,15:09:44,15:09:44,8,148400,53672,cap-wifi3,-63,412900000,344100000,981232,603784,00:10:10,00:00:00
|
||||
1788527386,15:09:46,15:09:46,2,97568,37160,cap-wifi3,-62,412900000,309700000,225464,141192,00:10:12,00:00:00
|
||||
1788527388,15:09:48,15:09:48,4,76456,19280,cap-wifi3,-62,412900000,309700000,225464,141192,00:10:14,00:00:00
|
||||
1788527390,15:09:50,15:09:50,17,74488,14496,cap-wifi3,-63,344100000,275300000,731840,568104,00:10:16,00:00:00
|
||||
1788527392,15:09:52,15:09:52,9,81688,114120,cap-wifi3,-64,412900000,309700000,217144,287216,00:10:18,00:00:00
|
||||
1788527394,15:09:54,15:09:54,11,139472,94312,cap-wifi3,-64,412900000,309700000,217144,287216,00:10:20,00:00:00
|
||||
1788527396,15:09:56,15:09:56,8,99376,34800,cap-wifi3,-63,412900000,344100000,522856,417128,00:10:22,00:00:00
|
||||
1788527398,15:09:58,15:09:58,7,95624,20936,cap-wifi3,-64,412900000,344100000,1177520,673088,00:10:24,00:00:00
|
||||
1788527400,15:10:00,15:10:00,11,75688,17080,cap-wifi3,-64,412900000,344100000,1177520,673088,00:10:26,00:00:00
|
||||
1788527402,15:10:02,15:10:02,8,194448,59984,cap-wifi3,-62,412900000,412900000,1678424,596296,00:10:28,00:00:00
|
||||
1788527404,15:10:04,15:10:04,5,87848,23392,cap-wifi3,-62,412900000,412900000,1099136,718696,00:10:30,00:00:00
|
||||
1788527406,15:10:06,15:10:06,4,102440,31824,cap-wifi3,-62,412900000,412900000,1099136,718696,00:10:32,00:00:00
|
||||
1788527408,15:10:08,15:10:08,7,140352,49312,cap-wifi3,-65,412900000,309700000,944912,595928,00:10:34,00:00:00
|
||||
1788527410,15:10:10,15:10:10,20,81216,18128,cap-wifi3,-64,455800000,344100000,1466688,782256,00:10:36,00:00:00
|
||||
1788527412,15:10:12,15:10:12,8,223088,23248,cap-wifi3,-64,455800000,344100000,1466688,782256,00:10:38,00:00:00
|
||||
1788527414,15:10:14,15:10:14,7,139784,51840,cap-wifi3,-63,412900000,344100000,1572056,878688,00:10:40,00:00:00
|
||||
1788527415,15:10:15,RECONNECT
|
||||
|
1
docs/messdaten/tp25-runde-dauerping/sampler-macbook.out
Normal file
1
docs/messdaten/tp25-runde-dauerping/sampler-macbook.out
Normal file
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-macbook.csv (Takt 2s, Client 56:71:6C:22:E6:A9)
|
||||
@@ -0,0 +1,2 @@
|
||||
14:58:12 Verbindung weg -- neuer Versuch in 2 s
|
||||
15:10:15 Verbindung weg -- neuer Versuch in 2 s
|
||||
130
docs/messdaten/tp25-runde-dauerping/sampler-s22.csv
Normal file
130
docs/messdaten/tp25-runde-dauerping/sampler-s22.csv
Normal file
@@ -0,0 +1,130 @@
|
||||
ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity
|
||||
1788527155,15:05:55,15:05:55,26,215104,164208,cap-wifi3,-50,6000000,6000000,0,0,00:00:50,00:00:18.020
|
||||
1788527157,15:05:57,15:05:57,10,230144,103104,cap-wifi3,-49,309700000,344100000,63424,67648,00:00:52,00:00:00
|
||||
1788527159,15:05:59,15:05:59,27,997352,175928,cap-wifi3,-49,309700000,344100000,63424,67648,00:00:55,00:00:00
|
||||
1788527161,15:06:01,15:06:01,5,496624,179032,cap-wifi3,-49,309700000,344100000,2800,2960,00:00:57,00:00:00
|
||||
1788527163,15:06:03,15:06:03,7,112272,25664,cap-wifi3,-49,309700000,344100000,2800,2960,00:00:59,00:00:00
|
||||
1788527165,15:06:05,15:06:06,6,353280,101384,cap-wifi3,-49,309700000,344100000,2800,2960,00:01:01,00:00:00
|
||||
1788527168,15:06:08,15:06:08,6,137256,37360,cap-wifi3,-53,309700000,344100000,5472,4672,00:01:03,00:00:00
|
||||
1788527170,15:06:10,15:06:10,18,373144,1851168,cap-wifi3,-61,275300000,206500000,2800,2960,00:01:05,00:00:00
|
||||
1788527172,15:06:12,15:06:12,2,79504,15688,cap-wifi3,-61,275300000,206500000,2800,2960,00:01:07,00:00:00
|
||||
1788527174,15:06:14,15:06:14,6,215576,3512448,cap-wifi3,-56,154900000,258100000,3592,4872,00:01:09,00:00:00
|
||||
1788527176,15:06:16,15:06:16,4,170440,37144,cap-wifi3,-51,24000000,229400000,2800,10960,00:01:11,00:00:00
|
||||
1788527178,15:06:18,15:06:18,7,187488,1860720,cap-wifi3,-51,24000000,229400000,2800,10960,00:01:13,00:00:00
|
||||
1788527180,15:06:20,15:06:20,21,418584,3563696,cap-wifi3,-52,275300000,258100000,2800,2960,00:01:15,00:00:00
|
||||
1788527182,15:06:22,15:06:22,6,91920,32648,cap-wifi3,-51,275300000,286800000,2800,10960,00:01:17,00:00:00
|
||||
1788527184,15:06:24,15:06:24,8,229720,340576,cap-wifi3,-51,275300000,286800000,2800,10960,00:01:19,00:00:00
|
||||
1788527186,15:06:26,15:06:26,11,324680,63616,cap-wifi3,-52,275300000,286800000,4184,4376,00:01:21,00:00:00
|
||||
1788527188,15:06:28,15:06:28,7,323944,57120,cap-wifi3,-50,275300000,309700000,3360,3552,00:01:23,00:00:00
|
||||
1788527190,15:06:30,15:06:30,7,89536,26840,cap-wifi3,-50,275300000,309700000,3360,3552,00:01:25,00:00:00
|
||||
1788527192,15:06:32,15:06:32,6,88056,17368,cap-wifi3,-50,275300000,344100000,5344,8864,00:01:27,00:00:00
|
||||
1788527194,15:06:34,15:06:34,6,78232,15688,cap-wifi3,-52,275300000,309700000,3248,3328,00:01:29,00:00:00
|
||||
1788527196,15:06:36,15:06:36,6,77824,19488,cap-wifi3,-52,275300000,309700000,3248,3328,00:01:31,00:00:00
|
||||
1788527198,15:06:38,15:06:38,8,91648,29960,cap-wifi3,-58,275300000,344100000,2800,2960,00:01:33,00:00:00
|
||||
1788527200,15:06:40,15:06:40,6,479584,403096,cap-wifi3,-51,275300000,229400000,2800,2960,00:01:35,00:00:00
|
||||
1788527202,15:06:42,15:06:42,5,83504,18032,cap-wifi3,-51,275300000,229400000,2800,2960,00:01:37,00:00:00
|
||||
1788527204,15:06:44,15:06:44,12,94312,27480,cap-wifi3,-54,275300000,258100000,2800,2960,00:01:39,00:00:00
|
||||
1788527206,15:06:46,15:06:46,11,104592,25288,cap-wifi3,-53,275300000,286800000,2800,10960,00:01:41,00:00:00
|
||||
1788527208,15:06:48,15:06:48,9,77672,15824,cap-wifi3,-52,24000000,286800000,2800,2960,00:01:43,00:00:00
|
||||
1788527210,15:06:50,15:06:50,8,130536,65520,cap-wifi3,-52,24000000,286800000,2800,2960,00:01:46,00:00:00
|
||||
1788527212,15:06:52,15:06:52,6,179704,71320,cap-wifi3,-53,6000000,286800000,3360,3552,00:01:48,00:00:00
|
||||
1788527214,15:06:54,15:06:54,7,150376,135320,cap-wifi3,-51,275300000,309700000,2800,2960,00:01:50,00:00:00
|
||||
1788527216,15:06:56,15:06:57,7,180576,117008,cap-wifi3,-51,275300000,309700000,2800,2960,00:01:52,00:00:00
|
||||
1788527219,15:06:59,15:06:59,9,81080,17128,cap-wifi3,-52,275300000,309700000,2800,2960,00:01:54,00:00:00
|
||||
1788527221,15:07:01,15:07:01,6,267072,71760,cap-wifi3,-51,275300000,309700000,2800,2960,00:01:56,00:00:00
|
||||
1788527223,15:07:03,15:07:03,7,229720,79648,cap-wifi3,-51,275300000,309700000,2800,2960,00:01:58,00:00:00
|
||||
1788527225,15:07:05,15:07:05,12,613656,242376,cap-wifi3,-53,275300000,344100000,2800,2960,00:02:00,00:00:00
|
||||
1788527227,15:07:07,15:07:07,9,136256,40080,cap-wifi3,-52,275300000,344100000,3808,3920,00:02:02,00:00:00
|
||||
1788527229,15:07:09,15:07:09,11,113040,49536,cap-wifi3,-52,275300000,344100000,3808,3920,00:02:04,00:00:00
|
||||
1788527231,15:07:11,15:07:11,7,85432,17976,cap-wifi3,-53,275300000,309700000,2800,2960,00:02:06,00:00:00
|
||||
1788527233,15:07:13,15:07:13,5,81944,26128,cap-wifi3,-56,275300000,286800000,2800,3552,00:02:08,00:00:00
|
||||
1788527235,15:07:15,15:07:15,5,954264,397144,cap-wifi3,-56,275300000,286800000,2800,3552,00:02:10,00:00:00
|
||||
1788527237,15:07:17,15:07:17,12,3430312,274976,cap-wifi3,-50,275300000,344100000,11168,29128,00:02:12,00:00:00
|
||||
1788527239,15:07:19,15:07:19,21,5774264,240088,cap-wifi3,-50,275300000,344100000,3360,3552,00:02:14,00:00:00
|
||||
1788527241,15:07:21,15:07:21,7,419688,124632,cap-wifi3,-50,275300000,344100000,3360,3552,00:02:16,00:00:00
|
||||
1788527243,15:07:23,15:07:23,6,146872,47152,cap-wifi3,-50,275300000,344100000,2800,2960,00:02:18,00:00:00
|
||||
1788527245,15:07:25,15:07:25,6,469520,144920,cap-wifi3,-50,275300000,344100000,2800,2960,00:02:20,00:00:00
|
||||
1788527247,15:07:27,15:07:27,8,87480,21512,cap-wifi3,-50,275300000,344100000,2800,2960,00:02:22,00:00:00
|
||||
1788527249,15:07:29,15:07:29,20,89592,20496,cap-wifi3,-50,275300000,344100000,3360,3552,00:02:24,00:00:00
|
||||
1788527251,15:07:31,15:07:31,9,77304,18144,cap-wifi3,-50,275300000,344100000,2800,2960,00:02:26,00:00:00
|
||||
1788527253,15:07:33,15:07:33,7,84240,17432,cap-wifi3,-50,275300000,344100000,2800,2960,00:02:28,00:00:00
|
||||
1788527255,15:07:35,15:07:35,9,74928,18888,cap-wifi3,-51,275300000,344100000,2240,2368,00:02:30,00:00:00
|
||||
1788527257,15:07:37,15:07:37,12,79856,17376,cap-wifi3,-51,275300000,344100000,2800,2960,00:02:33,00:00:00
|
||||
1788527259,15:07:39,15:07:39,19,91680,31720,cap-wifi3,-52,275300000,344100000,3808,3920,00:02:35,00:00:00
|
||||
1788527261,15:07:41,15:07:41,7,82760,21192,cap-wifi3,-52,275300000,344100000,3808,3920,00:02:37,00:00:00
|
||||
1788527263,15:07:43,15:07:44,6,91960,31680,cap-wifi3,-51,309700000,344100000,4912,4080,00:02:39,00:00:00
|
||||
1788527266,15:07:46,15:07:46,12,986832,256184,cap-wifi3,-51,309700000,344100000,3360,3552,00:02:41,00:00:00
|
||||
1788527268,15:07:48,15:07:48,8,204344,305984,cap-wifi3,-51,309700000,344100000,3360,3552,00:02:43,00:00:00
|
||||
1788527270,15:07:50,15:07:50,21,90376,25984,cap-wifi3,-50,309700000,412900000,2800,2960,00:02:45,00:00:00
|
||||
1788527272,15:07:52,15:07:52,9,106024,28632,cap-wifi3,-51,309700000,344100000,3360,3552,00:02:47,00:00:00
|
||||
1788527274,15:07:54,15:07:54,8,86752,24568,cap-wifi3,-51,309700000,344100000,3360,3552,00:02:49,00:00:00
|
||||
1788527276,15:07:56,15:07:56,8,68568,17040,cap-wifi3,-51,309700000,412900000,2800,2960,00:02:51,00:00:00
|
||||
1788527278,15:07:58,15:07:58,7,104792,53200,cap-wifi3,-48,206500000,344100000,3360,3552,00:02:53,00:00:00
|
||||
1788527280,15:08:00,15:08:00,17,304368,102592,cap-wifi3,-48,206500000,344100000,3360,3552,00:02:55,00:00:00
|
||||
1788527282,15:08:02,15:08:02,10,74432,14824,cap-wifi3,-49,206500000,344100000,2800,2960,00:02:57,00:00:00
|
||||
1788527284,15:08:04,15:08:04,15,84656,54904,cap-wifi3,-48,206500000,344100000,2800,2960,00:02:59,00:00:00
|
||||
1788527286,15:08:06,15:08:06,3,157752,48776,cap-wifi3,-48,206500000,344100000,2800,2960,00:03:01,00:00:00
|
||||
1788527288,15:08:08,15:08:08,6,93880,28544,cap-wifi3,-48,206500000,344100000,3360,3552,00:03:03,00:00:00
|
||||
1788527290,15:08:10,15:08:10,5,92704,21680,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:05,00:00:00
|
||||
1788527292,15:08:12,15:08:12,4,1096952,456376,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:07,00:00:00
|
||||
1788527294,15:08:14,15:08:14,5,96296,34168,cap-wifi3,-48,206500000,344100000,2800,2960,00:03:09,00:00:00
|
||||
1788527296,15:08:16,15:08:16,4,323536,108008,cap-wifi3,-48,206500000,344100000,4184,4376,00:03:11,00:00:00
|
||||
1788527298,15:08:18,15:08:18,5,106776,31872,cap-wifi3,-48,206500000,344100000,4184,4376,00:03:13,00:00:00
|
||||
1788527300,15:08:20,15:08:20,5,180440,70648,cap-wifi3,-49,206500000,344100000,3360,3552,00:03:15,00:00:00
|
||||
1788527302,15:08:22,15:08:22,5,258520,122376,cap-wifi3,-49,206500000,344100000,2800,10960,00:03:17,00:00:00
|
||||
1788527304,15:08:24,15:08:24,8,484544,159104,cap-wifi3,-49,206500000,344100000,2800,10960,00:03:19,00:00:00
|
||||
1788527306,15:08:26,15:08:26,5,85832,21400,cap-wifi3,-48,206500000,344100000,3360,2960,00:03:21,00:00:00
|
||||
1788527308,15:08:28,15:08:28,7,86968,23984,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:24,00:00:00
|
||||
1788527310,15:08:30,15:08:30,4,92848,27216,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:26,00:00:00
|
||||
1788527312,15:08:32,15:08:32,13,88112,30272,cap-wifi3,-49,206500000,344100000,3360,3552,00:03:28,00:00:00
|
||||
1788527314,15:08:34,15:08:35,6,97568,38688,cap-wifi3,-50,206500000,344100000,2800,2960,00:03:30,00:00:00
|
||||
1788527317,15:08:37,15:08:37,7,69376,15424,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:32,00:00:00
|
||||
1788527319,15:08:39,15:08:39,7,95672,27872,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:34,00:00:00
|
||||
1788527321,15:08:41,15:08:41,8,81008,14064,cap-wifi3,-49,206500000,344100000,3360,3552,00:03:36,00:00:00
|
||||
1788527323,15:08:43,15:08:43,8,79480,19824,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:38,00:00:00
|
||||
1788527325,15:08:45,15:08:45,6,83080,28888,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:40,00:00:00
|
||||
1788527327,15:08:47,15:08:47,9,77224,19568,cap-wifi3,-49,206500000,309700000,3360,3552,00:03:42,00:00:00
|
||||
1788527329,15:08:49,15:08:49,7,87976,23544,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:44,00:00:00
|
||||
1788527331,15:08:51,15:08:51,6,99288,43960,cap-wifi3,-49,206500000,344100000,2800,2960,00:03:46,00:00:00
|
||||
1788527333,15:08:53,15:08:53,7,78784,16504,cap-wifi3,-45,206500000,309700000,2800,2960,00:03:48,00:00:00
|
||||
1788527335,15:08:55,15:08:55,8,100664,43024,cap-wifi3,-60,206500000,309700000,2800,2960,00:03:50,00:00:00
|
||||
1788527337,15:08:57,15:08:57,6,75392,68792,cap-wifi3,-60,206500000,309700000,2800,2960,00:03:52,00:00:00
|
||||
1788527339,15:08:59,15:08:59,18,84648,23296,cap-wifi3,-58,206500000,309700000,2800,2960,00:03:54,00:00:00
|
||||
1788527341,15:09:01,15:09:01,5,146608,49608,cap-wifi3,-54,6000000,6000000,3360,3552,00:03:56,00:00:00
|
||||
1788527343,15:09:03,15:09:03,6,271512,52760,cap-wifi3,-54,6000000,6000000,3360,3552,00:03:58,00:00:00
|
||||
1788527345,15:09:05,15:09:05,6,400696,3660640,cap-wifi3,-56,275300000,344100000,2800,2960,00:04:00,00:00:00
|
||||
1788527347,15:09:07,15:09:07,6,131696,25096,cap-wifi3,-54,275300000,344100000,3360,3552,00:04:02,00:00:00
|
||||
1788527349,15:09:09,15:09:09,19,174312,46976,cap-wifi3,-54,275300000,344100000,3360,3552,00:04:04,00:00:00
|
||||
1788527351,15:09:11,15:09:11,6,359504,63184,cap-wifi3,-54,275300000,309700000,2800,2960,00:04:06,00:00:00
|
||||
1788527353,15:09:13,15:09:13,8,181920,63704,cap-wifi3,-58,24000000,344100000,2800,4896,00:04:08,00:00:00
|
||||
1788527355,15:09:15,15:09:15,5,306368,67704,cap-wifi3,-58,24000000,344100000,2800,4896,00:04:10,00:00:00
|
||||
1788527357,15:09:17,15:09:17,7,306688,60896,cap-wifi3,-57,275300000,309700000,3656,3520,00:04:12,00:00:00
|
||||
1788527359,15:09:19,15:09:19,19,310240,63104,cap-wifi3,-57,154900000,309700000,4384,6048,00:04:14,00:00:00
|
||||
1788527361,15:09:21,15:09:21,10,228704,92160,cap-wifi3,-57,154900000,309700000,4384,6048,00:04:16,00:00:00
|
||||
1788527363,15:09:23,15:09:23,7,292296,160184,cap-wifi3,-61,154900000,309700000,10568,37976,00:04:18,00:00:00
|
||||
1788527365,15:09:25,15:09:25,5,695128,395648,cap-wifi3,-56,154900000,309700000,3360,3552,00:04:20,00:00:00
|
||||
1788527367,15:09:27,15:09:27,6,123816,28072,cap-wifi3,-56,154900000,309700000,3360,3552,00:04:22,00:00:00
|
||||
1788527369,15:09:29,15:09:29,19,124944,35616,cap-wifi3,-57,154900000,344100000,2800,2960,00:04:24,00:00:00
|
||||
1788527371,15:09:31,15:09:31,5,171352,44496,cap-wifi3,-57,154900000,275300000,4040,6584,00:04:26,00:00:00
|
||||
1788527373,15:09:33,15:09:33,6,166240,43784,cap-wifi3,-57,154900000,275300000,4040,6584,00:04:28,00:00:00
|
||||
1788527375,15:09:35,15:09:35,6,150760,49464,cap-wifi3,-56,154900000,309700000,2800,2960,00:04:31,00:00:00
|
||||
1788527377,15:09:37,15:09:37,10,185768,47120,cap-wifi3,-57,24000000,309700000,2800,2960,00:04:33,00:00:00
|
||||
1788527379,15:09:39,15:09:39,18,190032,49512,cap-wifi3,-57,24000000,309700000,2800,2960,00:04:35,00:00:00
|
||||
1788527381,15:09:41,15:09:41,8,97808,22304,cap-wifi3,-57,154900000,344100000,2800,2960,00:04:37,00:00:00
|
||||
1788527383,15:09:43,15:09:43,8,148400,53672,cap-wifi3,-57,154900000,344100000,2800,2960,00:04:39,00:00:00
|
||||
1788527386,15:09:46,15:09:46,2,97568,37160,cap-wifi3,-57,154900000,344100000,2800,2960,00:04:41,00:00:00
|
||||
1788527387,15:09:47,15:09:48,4,76456,19280,cap-wifi3,-57,154900000,309700000,2800,3552,00:04:43,00:00:00
|
||||
1788527389,15:09:49,15:09:50,17,74488,14496,cap-wifi3,-58,6000000,309700000,2800,2960,00:04:45,00:00:00
|
||||
1788527392,15:09:52,15:09:52,4,81688,114120,cap-wifi3,-58,6000000,309700000,2800,2960,00:04:47,00:00:00
|
||||
1788527394,15:09:54,15:09:54,8,139472,94312,cap-wifi3,-57,154900000,309700000,2800,2960,00:04:49,00:00:00
|
||||
1788527396,15:09:56,15:09:56,4,99376,34800,cap-wifi3,-57,154900000,309700000,2800,2960,00:04:51,00:00:00
|
||||
1788527398,15:09:58,15:09:58,5,95624,20936,cap-wifi3,-57,154900000,309700000,2800,2960,00:04:53,00:00:00
|
||||
1788527400,15:10:00,15:10:00,19,75688,17080,cap-wifi3,-57,154900000,344100000,2800,2960,00:04:55,00:00:00
|
||||
1788527402,15:10:02,15:10:02,12,194448,59984,cap-wifi3,-56,154900000,344100000,2800,2960,00:04:57,00:00:00
|
||||
1788527404,15:10:04,15:10:04,10,87848,23392,cap-wifi3,-58,154900000,344100000,2800,2960,00:04:59,00:00:00
|
||||
1788527406,15:10:06,15:10:06,9,102440,31824,cap-wifi3,-58,154900000,344100000,2800,2960,00:05:01,00:00:00
|
||||
1788527408,15:10:08,15:10:08,8,140352,49312,cap-wifi3,-56,154900000,309700000,2800,2960,00:05:03,00:00:00
|
||||
1788527410,15:10:10,15:10:10,25,88352,30376,cap-wifi3,-56,154900000,309700000,2800,2960,00:05:05,00:00:00
|
||||
1788527412,15:10:12,15:10:12,7,124328,46808,cap-wifi3,-56,154900000,309700000,2800,2960,00:05:07,00:00:00
|
||||
1788527414,15:10:14,15:10:14,8,84784,23040,cap-wifi3,-57,154900000,344100000,2800,2960,00:05:09,00:00:00
|
||||
1788527415,15:10:15,RECONNECT
|
||||
|
1
docs/messdaten/tp25-runde-dauerping/sampler-s22.out
Normal file
1
docs/messdaten/tp25-runde-dauerping/sampler-s22.out
Normal file
@@ -0,0 +1 @@
|
||||
Sampler laeuft -> /Users/christophemsenhuber/dev/bf-infra/docs/messdaten/tp25-runde-dauerping/sampler-s22.csv (Takt 2s, Client 2A:0D:B0:5D:AD:A7)
|
||||
@@ -0,0 +1,2 @@
|
||||
14:58:12 Verbindung weg -- neuer Versuch in 2 s
|
||||
15:10:15 Verbindung weg -- neuer Versuch in 2 s
|
||||
0
docs/messdaten/tp25-runde-dauerping/stop.flag
Normal file
0
docs/messdaten/tp25-runde-dauerping/stop.flag
Normal file
1280
docs/messdaten/tp25-runde-dauerping/walk-ping-ipad.csv
Normal file
1280
docs/messdaten/tp25-runde-dauerping/walk-ping-ipad.csv
Normal file
File diff suppressed because it is too large
Load Diff
1299
docs/messdaten/tp25-runde-dauerping/walk-ping-iphone.csv
Normal file
1299
docs/messdaten/tp25-runde-dauerping/walk-ping-iphone.csv
Normal file
File diff suppressed because it is too large
Load Diff
1304
docs/messdaten/tp25-runde-dauerping/walk-ping-macbook.csv
Normal file
1304
docs/messdaten/tp25-runde-dauerping/walk-ping-macbook.csv
Normal file
File diff suppressed because it is too large
Load Diff
1302
docs/messdaten/tp25-runde-dauerping/walk-ping-s22.csv
Normal file
1302
docs/messdaten/tp25-runde-dauerping/walk-ping-s22.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,12 @@ teuerste Eigenschaft der Datei zerstört, um ihr billigstes Problem zu lösen. B
|
||||
| [TP27](#tp27) | RouterBOOT-Firmware auf 7.24 nachziehen | ✅ DURCH (2026-08-17/18) |
|
||||
| [TP28](#tp28) | WLAN über CAPsMAN auf `crs326-core` | ↩️ **wieder geöffnet 2026-08-30** (ap3) — Volltext in [teilprojekte.md](teilprojekte.md#tp28) |
|
||||
| [TP-R](#tp-r) | Router-Capabilities-Sweep | FERTIG (docs/research/routeros-capabilities.md) |
|
||||
| [TP39](#tp39) | LXC-Hygiene pve: Resolver-Altlasten, `networking.service`, DB-Reverse-Lookup | ✅ ABGESCHLOSSEN (2026-09-01) — pve+NAS-Sweep grün |
|
||||
| [TP34](#tp34) | Caddyfile via Nautobot/GC (generische Reverse-Proxy-Schnittstelle) | ❌ VERWORFEN (2026-09-08) — Caddyfile bleibt manuell |
|
||||
| [TP44](#tp44) | Cloudflare-Estate als Dokumentations-SSoT in Nautobot | ✅ DURCH (2026-09-10) |
|
||||
| [TP41](#tp41) | CF-Access-Reparatur + Zero-Trust-Konsolidierung | ✅ ABGESCHLOSSEN (2026-09-10) — Gelis WARP via Android eingerichtet, letzter Blocker weg |
|
||||
| [TP43](#tp43) | dw-Standort-DNS-Uplink (site-spezifische Overrides) | ♻️ REOPENED (2026-09-11) — Volltext zurück in teilprojekte.md; interne BF-Namen über WG am dw offen |
|
||||
| [TP42](#tp42) | Namens-Vereinheitlichung: ein interner Suffix bf.emsenhuber.net | ✅ DURCH (2026-09-02) — `.bf.lan` raus, `.16` abgebaut, Compliance 140/140 |
|
||||
|
||||
Dazu am Ende: **[TP25 (Langfassung)](#tp25-lang)** — die Messchronik und die Funde A–E im Volltext.
|
||||
TP25 selbst ist **nicht** abgeschlossen und steht weiter in `teilprojekte.md`; nur seine 394 Zeilen
|
||||
@@ -1697,3 +1703,277 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
|
||||
2026-08-13 gemessen: ap1 25→2, ap2 7→14). **Nicht während eines Calls deployen.** `/system backup` je AP vorher.
|
||||
- **Abh.:** TP22 ✅ (GC-Deploy-Pipeline). Übernimmt den offenen Rest von **TP3.3**, verwandt **TP3.2** (Coverage-Doku
|
||||
`docs/wifi-p750w-coverage-and-map.md`). **Kein Blocker für TP5/TP6** — läuft parallel.
|
||||
|
||||
<a id="tp39"></a>
|
||||
|
||||
### TP39 — LXC-Hygiene auf pve: Resolver-Altlasten, `networking.service`, DB-Reverse-Lookup ▸ ✅ **ABGESCHLOSSEN (2026-09-01)**
|
||||
|
||||
**Auslöser:** ein 10-Sekunden-Hänger auf `gitea`, gefunden am Rand des TP16.3-§5-Flips. Er hatte mit
|
||||
dem Flip nichts zu tun, war aber nur deshalb sichtbar, weil zum ersten Mal jemand systematisch
|
||||
gemessen hat. Beim Beheben kam eine zweite, unabhängige Altlast zum Vorschein. Beide sind
|
||||
**Hygiene an denselben pve-LXCs** und gehören in **ein** Wartungsfenster — deshalb ein TP, nicht zwei.
|
||||
|
||||
#### Was am 2026-09-01 bereits erledigt ist (Ausgangslage, nicht Aufgabe)
|
||||
|
||||
- **Ursache des Hängers:** MariaDB (LXC **302**, `10.40.20.23`) hatte `skip-name-resolve`
|
||||
**auskommentiert** ⇒ Reverse-Lookup bei **jeder neuen Verbindung**; `/etc/resolv.conf` zeigte auf
|
||||
den **toten** `10.40.41.254` (VLAN1-Altschema). **Gemessen: 10.010 ms je Lookup.**
|
||||
Pool-Verbindungen waren schnell ⇒ das Symptom wirkte sporadisch.
|
||||
- **Blast-Radius, per Verbindungstabelle belegt:** an dieser DB hängen **Vaultwarden (`.127`),
|
||||
Home Assistant (`.105`) und gitea (`.157`)**.
|
||||
- **Fix ausgerollt** (`pct set <id> --nameserver 10.40.20.1` + Reboot) für **fünf** LXCs:
|
||||
`302 mariadb`, `102 mqtt5`, `106 influxdb2`, `107 redis`, `150 iob-exposed`.
|
||||
**Nachher: Lookup 21–24 ms, gitea 0 von 25 Proben langsam** (vorher ~10 % bei 10,1 s).
|
||||
|
||||
#### Scope (alle Punkte erledigt)
|
||||
|
||||
1. ✅ **ERLEDIGT 2026-09-01: `skip-name-resolve` aktiviert.** Vorher `mysql.user` gelesen (User gab
|
||||
den DB-Zugang per `/root/.my.cnf`) — **kein einziger Grant lautet auf einen DNS-Hostnamen**, alle
|
||||
sind `%` / IP-Literal / `localhost`. Damit kann `skip-name-resolve` niemanden aussperren; der
|
||||
Reverse-Lookup war reiner Ballast. Gesetzt als eigenes Drop-in
|
||||
`/etc/mysql/mariadb.conf.d/90-skip-name-resolve.cnf` (nicht die `#`-Zeile in `50-server.cnf`
|
||||
editiert — Paket-Update-stabil), `@@skip_name_resolve=1` nach Neustart verifiziert.
|
||||
**Wirkung: gitea/vw/hass je 0 von 12 frischen Anfragen langsam, max 0,25 s.** Alle drei Clients
|
||||
danach wieder verbunden. Die Ursache ist damit **beseitigt**, nicht nur entschärft.
|
||||
🔴 **Sicherheitsvorfall dabei:** die `.my.cnf` trug `password <wert>` **ohne `=`**, die Maskierung
|
||||
griff nicht ⇒ das **root-DB-Passwort ist ins Transkript geraten** und gehört rotiert (→ TP30).
|
||||
2. ✅ **ERLEDIGT 2026-09-01: `networking.service` + `ifupdown-wait-online.service` in `101`, `102`,
|
||||
`106`, `107` repariert.** **Ursache — dieselbe Altlast wie beim Resolver:** in
|
||||
`/etc/network/interfaces` standen noch `auto`-Stanzas aus dem **alten VLAN1-Schema**
|
||||
(`eth0` → `10.40.41.x`) und aus früheren Versuchen (`veth16`, `veth24`, ein Tippfehler `eth01`) —
|
||||
**alle auf Interfaces, die es im Container nicht gibt.** `ifup -a` scheiterte daran, während das
|
||||
echte `veth20` sauber hochkam: „failed" bei funktionierendem Netz.
|
||||
**Fix:** nur die toten Stanzas entfernt (Backup je Container:
|
||||
`/etc/network/interfaces.bak-20260901`), `lo`/`veth20`/`veth20.2` unangetastet.
|
||||
**Beweis ist ein echter Neustart, nicht der Servicestatus:** `106` neu gestartet ⇒ **influxdb kam
|
||||
nach 5 s von selbst hoch**, `networking active`, **null** fehlgeschlagene Units. Genau der Fall,
|
||||
der vorher scheiterte.
|
||||
🔑 **Nicht durch die Session verursacht:** `101` wurde vor dem Fix nie angefasst und zeigte dasselbe
|
||||
Bild — die Container liefen nur 13+ Tage ohne Neustart, deshalb war es unsichtbar.
|
||||
🟡 **Rest, bewusst liegen gelassen:** `run-rpc_pipefs.mount` (101, 150) und
|
||||
`proxmox-regenerate-snakeoil.service` (108) — vorbestehend, ohne Bezug zu Netz oder DNS.
|
||||
3. ✅ **ERLEDIGT 2026-09-01 (im selben Fenster aufgetaucht): LXC 302 war zu 100 % voll** (62/65 GB),
|
||||
Rootfs `+30G` online gewachsen ⇒ 95 GB / 69 %, MariaDB lief durch. 🔴 **Das ist ein Puffer, kein
|
||||
Fix:** 59 GB davon sind die `homeassistant`-DB (`states.ibd` allein **41 GB**), die unbegrenzt
|
||||
wächst (~1 GB/Tag) — die dauerhafte Lösung ist HA-seitig und liegt in **TP40**.
|
||||
4. ✅ **ERLEDIGT 2026-09-01: Resolver-Sweep durchgezogen — pve UND NAS.** **pve:** alle 13 LXCs
|
||||
(`101,102,105,106,107,108,110,111,112,130,150,302,400`) tragen `nameserver 10.40.20.1`, **kein
|
||||
`.41.254` mehr** — nicht nur die fünf geänderten. **NAS (DS923) via Portainer-API ep14:** alle
|
||||
20 Container gelistet, keiner mit `.41.254`-DNS-Override; alle laufenden lösen über den
|
||||
Embedded-Resolver (`127.0.0.11`) in **66–110 ms** auf (rc=0), inkl. Grenzfall `gitea` (erstellt
|
||||
2026-07-10, um den Host-Fix herum) — **kein eingefrorener Dead-Resolver**, kein Recreate nötig.
|
||||
NAS-Host `/etc/resolv.conf` = `10.40.20.1`. Als **wiederkehrende Kontrolle** bleibt der Sweep als
|
||||
CLAUDE.md-Gotcha verankert (pve-Einzeiler + Synology-DSM-Fallstrick von 2026-07-10).
|
||||
5. ✅ **ERLEDIGT 2026-09-01: Abnahme-Regel festgeschrieben.** „Vor jedem geplanten LXC-Neustart
|
||||
`systemctl --failed` lesen und danach die **Ports gegen vorher** vergleichen" steht als
|
||||
CLAUDE.md-Gotcha (Fall `influxdb2` wäre sonst still durchgerutscht).
|
||||
|
||||
#### Abhängigkeiten
|
||||
|
||||
- Keine blockierenden. Punkt 1 brauchte **DB-Credentials** (siehe **TP30**, Credential-Bestand).
|
||||
- Punkt 2 war unabhängig und lief zuerst.
|
||||
|
||||
#### Abgrenzung
|
||||
|
||||
- **Nicht** TP16.3: dort geht es um cloudflared/Tunnel: der DNS-Fund kam nur *dabei* ans Licht.
|
||||
- **Nicht** TP14.2a: das war 2026-07-10 derselbe Fehlertyp an **anderen** Hosts (NAS + LXC 400) und
|
||||
ist abgeschlossen. **Dass er hier erneut auftrat, ist genau die Begründung für Punkt 4:**
|
||||
die Klasse wurde damals an den bekannten Stellen behoben, nie im Bestand gesucht.
|
||||
- **Nicht** TP31/TP34 (Caddy) und nicht TP11 (Monitoring) — obwohl gilt: ein Monitoring, das
|
||||
DB-Verbindungszeiten kennt, hätte diesen Fall Monate früher gezeigt.
|
||||
- **Nicht** TP40: der HA-Recorder-Wildwuchs (Punkt 3) ist HA-seitig und ein eigenes TP.
|
||||
|
||||
---
|
||||
|
||||
### TP34 — Caddyfile via Nautobot/GC (generische Reverse-Proxy-Schnittstelle) ▸ ❌ **VERWORFEN (2026-09-08)**
|
||||
> 🔴 **Nachtrag 2026-09-08 (verworfen):** Der Ansatz „Caddyfile via Golden Config rendern" ist
|
||||
> zurückgezogen (Commits `d63dc7b`, `bca8f6e`; Gitea-Issue #24 → `status:dropped`, closed). Der
|
||||
> `420.teilzeitladen.xyz`-Block wurde wieder aus dem GC-gerenderten Caddyfile entfernt; **der
|
||||
> Caddyfile bleibt manuell** in `caddy/Caddyfile`. Gründe: kein zweites SSoT-Modell für Proxy-Routen
|
||||
> nötig, TP37 deckt die Dienst-Doku als `ipam.Service` bereits ab, und der einzige akute Anwendungsfall
|
||||
> ließ sich mit einem manuellen Block lösen. Text unten unverändert als Konzept-Historie.
|
||||
|
||||
> **Konzept + Architektur-Skizze:** [`docs/handoff-20260827-inventur-und-architektur.md`](handoff-20260827-inventur-und-architektur.md) — bitte dort weiterlesen (Architektur-Abschnitt).
|
||||
- **Scope:** Reverse-Proxy-Hosts werden im **Nautobot-Datenmodell** gepflegt (Site, Host, Backend-Spec). **Golden Config** rendert den Caddyfile aus den Daten, Diff-Check gegen die Live-Version auf `caddy-bf1`, Compliance-Checks + Transaktionen identisch zum bestehenden Workflow für Router-Configs.
|
||||
- **Auslöser (Inventur 2026-08-27):** der Caddyfile (`bf-infra/caddy/Caddyfile`) ist heute **manuell gepflegt** — kein Drift-Check, keine Transaktionen, andere Projekte können keine Sites anlegen ohne Christoph. Lösung: **Nautobot/GC**, kein Caddy-API-Sidecar (kein zweites SSoT).
|
||||
- **Erster Anwendungsfall:** `terpene.teilzeitladen.xyz → http://10.40.20.167:8890` (Mac-mini-Backend, dort PostgREST + sync + web via lokalem Caddy `:8890`). Vor TP34: manueller Quick-Win-Caddy-Block.
|
||||
- **Abh.:** TP22 (GC-Pipeline) ✅ · TP23 (DNS/Caddy-Voraussetzungen) ✅ Stufe 1 · 🔴 **NEU 2026-09-06: TP37 Punkt 1+2** — Caddy rendert *Config aus Daten*, die Backend-Dienste müssen als `ipam.Service` in Nautobot existieren, sonst gibt es nichts zu rendern. **TP37 vor TP34.**
|
||||
- **Datenmodell (entschieden 2026-09-06):** native Modelle — Backend = `ipam.Service`, Proxy-Route = Relationship/CustomField Frontend↔Backend, GC-Job rendert den Caddyfile. Keine eigene App (konsistent zu TP44).
|
||||
- **Status:** 🔜 Stub; wartet auf TP37 P1+2. Quick-Win `terpene.teilzeitladen.xyz → 10.40.20.167:8890` als manueller Caddy-Block ist **Schritt 0** des Runbooks. Plan: [`handoff-20260906-tp37-34-36-plan.md`](handoff-20260906-tp37-34-36-plan.md).
|
||||
|
||||
---
|
||||
|
||||
<a id="tp44"></a>
|
||||
### TP44 — Cloudflare-Estate als Dokumentations-SSoT in Nautobot ▸ ✅ **DURCH (2026-09-10): Etappe 1 + Etappe 2 (Teil A IPAM-Prefixe, Teil B Live-Sync als täglicher Nautobot-Job)**
|
||||
> **Entscheid (User, 2026-09-02):** die volle CF-Estate (Tunnel + WARP-Connector + VPC-Service +
|
||||
> Hyperdrive + Workers + alle Access-Apps) als strukturierte, abfragbare SSoT in Nautobot abbilden —
|
||||
> **etappenweise: manuell jetzt, Sync später.** Nautobot kann CF nicht steuern → „SSoT" heißt
|
||||
> **Dokumentations-SSoT; CF bleibt operativer Master.** Detail-Handoff:
|
||||
> [`handoff-20260902-cf-estate-nautobot-ssot.md`](handoff-20260902-cf-estate-nautobot-ssot.md).
|
||||
|
||||
- **Warum eigenes TP, nicht TP36:** TP36 ist eng auf `teilprojekte.md`-Live-Daten geschnitten; gleiche
|
||||
Idee (Nautobot als Doku-SSoT), andere Dimension. TP44 = nächste freie Nummer nach TP43.
|
||||
- **Modell (native `nautobot.cloud`, Nautobot 3.1.7 — keine eigene App):** `Manufacturer "Cloudflare"` →
|
||||
`CloudAccount` (`393c051f…`) → `CloudResourceType ×6` → `CloudNetwork ×4` (`bf-public`/`fm`/`terpene-db`/
|
||||
`bf-core-mesh`) + `CloudService ×14`; Service↔Tunnel über das Through-Modell
|
||||
`cloud-service-network-assignments` (3 Rows). IDs/Ports/Hostnames/Origins je Objekt in `extra_config`.
|
||||
- **Werkzeug:** `nautobot/tp44-cf-estate-seed.py` — idempotenter Seeder (Re-Run = 26/26 „existiert"),
|
||||
Datenstand inline (Live-CF-Inventur 2026-09-02). Token aus `docs/nas-vlan20/stacks/210-nautobot.yml`.
|
||||
- ✅ **Verifikation 2026-09-06 (live gegen die API):** CloudAccount 1 · ResourceType 6 · CloudNetwork 4 ·
|
||||
CloudService 14 — unverändert seit 09-02.
|
||||
- 🔴 **Gotchas:** `CloudService.cloud_networks` ist `read_only` (nur Through-Rows schreiben/lesen) ·
|
||||
VPC-Service-API unter `connectivity/directory/services` (PUT, voller Body) · **VPC-Objekte tragen ihren
|
||||
Identifier in `service_id`, NICHT `id`** (kostete im Sync einen Fehl-Match) · ⚠️ **DRIFT-KORREKTUR
|
||||
2026-09-10:** die frühere Zeile „Repo-`CF_API_TOKEN` darf kein Workers-VPC → über den `cloudflare`-MCP"
|
||||
war **falsch**. Live getestet liest der `CF_API_TOKEN` aus `~/.secrets/credentials.env` Hyperdrive **und**
|
||||
VPC **und** Workers (alle 200). Der schmale Token ist `CF_DNS_API_TOKEN` (403). Der `cloudflare`-MCP ist
|
||||
der **remote OAuth-MCP** (kein API-Token) und für einen serverseitigen Job ohnehin nicht nutzbar.
|
||||
- ✅ **Etappe 2 Teil A (2026-09-08): IPAM-Prefixe live.** `10.40.0.0/16` (container, Route `bf-core-mesh`) +
|
||||
`10.101.0.0/24` (network, Route `fm`) angelegt via `nautobot/tp44-ipam-prefixes.py`; der Seeder-Re-Run
|
||||
hat die zwei `cloud-network-prefix-assignments` eingehängt (count=2, Idempotenz-Gegenprobe grün).
|
||||
- ✅ **Etappe 2 Teil B (2026-09-10): Live-Sync als Nautobot-Job — DURCH.** Governance (User 2026-09-09):
|
||||
periodische externe→Nautobot-Syncs leben als **Nautobot-Jobs** in `bf-infra/jobs/`, in Nautobot geplant —
|
||||
**kein per-Task-Container/-Cron.** Runtime `jobs/cf_estate_sync.py` (`CFEstateSync`, ORM, read-only Pull,
|
||||
403-tolerant, Verwaisung = `extra_config.stale` statt Löschen). Token = Nautobot-Secret `cf-api-token`
|
||||
(Provider env → `CF_API_TOKEN` am Worker, in `210-nautobot.yml` verdrahtet). **Schedule: täglich 03:00Z**
|
||||
(`ScheduledJob "CF Estate Sync – taeglich"`). Verifiziert: Dry-Run + Commit-Run sauber, **4 Networks /
|
||||
14 Services, alle Endpoints lesbar, 0 Drift**. Der REST-Einmalproof `nautobot/tp44-cf-sync.py` bleibt als
|
||||
workstation-seitiges Diagnose-Werkzeug liegen (nicht die kanonische Runtime).
|
||||
- 🔴 **Drei load-bearing Funde (Detail-Handoff `handoff-20260910-tp44-teilb-sync-live.md`):**
|
||||
(1) **Wurzel-`__init__.py` im Repo ist Pflicht** — Nautobot lädt Git-Repo-Jobs via
|
||||
`pkgutil.walk_packages([GIT_ROOT])`, das Namespace-Packages (ohne `__init__.py`) NICHT entdeckt; ohne die
|
||||
Datei bleibt `bf_infra.jobs` unsichtbar (Symptom: Sync SUCCESS + „No jobs were registered"). bf-infra ist
|
||||
das erste Git-Repo mit `extras.job`. (2) `register_jobs()` gehört ins **Paket-`__init__`**, nicht nur ins
|
||||
Submodul. (3) `Meta.has_sensitive_variables=False` nötig, sonst verweigert Nautobot das Scheduling.
|
||||
- **Beziehung zu TP37:** TP44 hat **TP37 Punkt 3** (CF-Connectoren) vorweggenommen — dieselbe native-Modell-
|
||||
Linie, die TP37 P1+2 (Substrat/Dienste) fortsetzt.
|
||||
|
||||
### TP41 — CF-Access-Reparatur + Zero-Trust-Konsolidierung ▸ ✅ **ABGESCHLOSSEN (2026-09-10)** — Auth-Kern seit 2026-09-01 komplett; **Gelis WARP-Client am 2026-09-10 via Android erfolgreich eingerichtet** (letzter Blocker weg, User-Bestätigung). Optionale Restpunkte (T6 Rate-Limit, geli-CGNAT-Policy-Cleanup) bewusst nicht gezogen; Keystore-Rotation läuft unter TP30 #7.
|
||||
|
||||
**Auslöser:** CF-Access zwang Christoph **und Geli** täglich zum OTP-Login (soll: 30 Tage); GitHub/Google
|
||||
„funktionieren nicht". Root-Causes: Team-Domain-Rename `bf4`→`emsenhuber` (Provider-Callback veraltet),
|
||||
App-Session 24h, diverse Ordnungs-/Sicherheitslecks. Vollständiger Verlauf + offene Schritte:
|
||||
**[`docs/handoff-20260901-tp41.md`](handoff-20260901-tp41.md)**. Branch `tp41-cf-access-repair`.
|
||||
|
||||
**✅ Live erledigt:** Session 720h (Wildcard/vw/Warp-Login) · login_method-Loch zu (reusable Policy
|
||||
`bf-users` = nur `email:christoph`+`email:geli`) · `8e44f5d1` von 4 Apps auf **nur Terpenfinder**
|
||||
entkoppelt · Access-**Gruppen** `zt-humans`/`zt-home`/`zt-automation`, Policies zeigen darauf · **vw voll
|
||||
Bypass** (Lebensader offen) + **`vw/admin` per WAF-Regel öffentlich geblockt** (CF-Edge + Mobilfunk
|
||||
verifiziert) · API-Token auf das vollständige `…4148` konsolidiert (User hat Service-Tokens- + Zero-Trust-
|
||||
Write ergänzt), altes `…2174` revoken.
|
||||
|
||||
**✅ T4 DURCH (2026-09-01, Variante B):** ein Access-Service-Token **`zt-svc`** (`65f1821a`, rotiert) über
|
||||
Gruppe `zt-automation`; Terpene-Worker per `wrangler secret put TERPENE_SVC_CLIENT_ID` auf zt-svc
|
||||
umgestellt (Worker-Pin `index.js:44`); `terpene-verify`+`-v2` **gelöscht**; `test_whoami` grün.
|
||||
**Token-Altlast geklärt:** `b00722` = LIVE Caddy-DNS-Token (LXC130 caddy.env, SSoT), `d47435` = stale
|
||||
Kopie (kein Consumer) → **User revoket `d47435`**; `credentials.env`-Kopie auf b00722 realignt.
|
||||
|
||||
**✅ T3 APPLIED (2026-09-01):** Default-Profil (`0197d1b3`; das custom „Cloudflare Mesh" matcht nur den
|
||||
`warp_connector`) `fallback_domains += emsenhuber.net → [10.40.20.36, 10.40.20.37]`; Tunnel-Route
|
||||
`10.40.0.0/16` (`d1da7c8a`) da, kein `10/8`-Exclude → routbar. ⏳ Client-Verify: WARP neu verbinden.
|
||||
**✅ T2 DURCH (2026-09-01):** WAF-Regel `f26744eb` gelöscht; Caddy `vw`-Block `respond @cf_admin 404` bei
|
||||
Header `CF-Connecting-IP` (LXC130). Verify: Edge `/admin`=404, lokal/WARP `/admin`=200. ✅
|
||||
|
||||
**✅ T5 DURCH (2026-09-01, User-bestätigt):** GitHub-Login läuft; Google-Login läuft nach dem
|
||||
Consent-Screen-Fix (§A des Follow-up-Handoffs: User Type *Internal*→*External*/veröffentlicht).
|
||||
Callback für beide `https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback`.
|
||||
**❌ Facebook/Meta für TP41 abgesagt (2026-09-01, User-Entscheid):** optional, kein Bedarf — Geli ist
|
||||
über OTP `angelikahy@outlook.de` + Google `pillepalle670@gmail.com` voll gedeckt. **Keine Facebook-App,
|
||||
kein CF-Facebook-IdP angelegt → nichts aufzuräumen.** Instagram hat ohnehin keinen CF-IdP.
|
||||
**✅ App-Launcher (D1):** je eine Bookmark-Kachel vw/hass/terpenfinder, Wildcard-Kachel raus, Launcher
|
||||
gestylt (Follow-up-Handoff §D, Policies unverändert).
|
||||
|
||||
**✅ Geli in WARP — CF-seitig nichts zu tun (2026-09-01 live geprüft):** Device-Enrollment läuft über
|
||||
die App **„Warp Login App"** (`6c32fe23…`, type `warp`) → Policy `bf-users` → Gruppe **`zt-humans`**, die
|
||||
Gelis beide Mails **schon enthält** → sie **darf bereits enrollen** (deshalb war „Device enrollment
|
||||
permissions" nicht als fehlendes Setting zu finden). Terpenfinder-`geli`-Policy lässt sie per E-Mail durch.
|
||||
✅ **Client am 2026-09-10 via Android erfolgreich eingerichtet** (WARP installiert, Team `emsenhuber`,
|
||||
Login OTP `angelikahy@outlook.de` — User-Bestätigung); damit ist der einzige verbliebene Handgriff erledigt.
|
||||
🔑 **Permission-Frage beantwortet:** CF-seitig **keine** nötig. Für generelle WARP/Enrollment/User-Verwaltung
|
||||
per Account-Token: *Access: Apps and Policies → Edit* + *Access: Organizations, IdPs, and Groups → Edit*
|
||||
(User erteilt 2026-09-01). **Seat-Verwaltung (`/access/seats`) bleibt per MCP gesperrt** — `10405 Method
|
||||
not allowed for this authentication scheme` (Endpoint will User-Token, nicht Account-Token; kein Scope-Fix,
|
||||
für Enroll irrelevant).
|
||||
|
||||
**🔻 Optionale Restpunkte (bewusst nicht gezogen, kein Blocker):** **T6** optional Rate-Limit ·
|
||||
🔴 `TERPENE_ANDROID_KEYSTORE_PW`-Rotation (→ **TP30 Posten #7**, Transkript-Leak) · **Security-Cleanup:**
|
||||
die `geli`-Terpenfinder-Policy hat **OR-Semantik** und enthält den breiten CGNAT-Bereich
|
||||
`94.154.138.0/24` als IP-Include → jeder aus dieser geteilten Range käme **ohne Login** rein. Über WARP ist
|
||||
der Egress ohnehin Cloudflare (nicht diese IP) → der IP-Include wäre dann überflüssig und entfernbar.
|
||||
**d47435-Revoke ✅ · T3-WARP-Client-Verify ✅** (User, 2026-09-01).
|
||||
|
||||
**Abgrenzung:** hass/gitea bleiben (diese Runde) öffentlich; Terpenfinder-Human-Policies nicht angefasst;
|
||||
**Gitea-Least-Privilege** = eigener künftiger TP (jedes Projekt repo-scoped Login, Admin nur Claude/Christoph).
|
||||
- Bezug **TP11** (Monitoring): eine Plattenfüllstand-Warnung hätte das Wochen früher gezeigt.
|
||||
|
||||
### TP43 — dw-Standort-DNS-Uplink (site-spezifische Overrides) ▸ ♻️ **REOPENED 2026-09-11 → Volltext zurück in [`teilprojekte.md`](teilprojekte.md) (Abschnitt TP43)**
|
||||
|
||||
Kurz zwischen 2026-09-11 verworfen und am selben Tag reopened: die 420-Prämisse war gegenstandslos
|
||||
(public CF-Worker, via WARP/TP41 gelöst), aber die **interne** BF-Namensauflösung über WG am dw blieb
|
||||
dabei offen (`portainer.bf.emsenhuber.net` am dw nicht erreichbar). Korrigierter Scope + verworfene
|
||||
420-Historie stehen jetzt aktiv in `teilprojekte.md`. Gitea-Issue #32 = `status:todo` · `thema:firewall-dns`.
|
||||
|
||||
### TP42 — Namens-Vereinheitlichung: ein interner Suffix bf.emsenhuber.net ▸ ✅ **DURCH (2026-09-02)** — ein interner Suffix `bf.emsenhuber.net`, `.bf.lan` raus, `.16` (adguard_bf1) abgebaut, Compliance 140/140. Offen nur der an **TP37** gekoppelte Nautobot-Doku-Teil.
|
||||
|
||||
**Auslöser (2026-09-01, TP41-Randbefund):** live gemessen liefern die realen Client-Resolver
|
||||
`10.40.20.36`/`.37` `*.emsenhuber.net → 10.40.20.40` (Caddy) — korrekt. Daneben existiert aber ein
|
||||
zweiter, gedrifteter interner Namensraum: der **Core** trägt in `/ip dns static` 11 Einträge auf
|
||||
`*.bf.lan`, der **Caddyfile** doppelt jeden internen Namen als `*.bf.emsenhuber.net`, und die alten
|
||||
AdGuard `.16`/`.17` antworten noch mit `nginx*.bf.emsenhuber.net` bzw. totem VLAN1 `10.40.41.123`.
|
||||
Christoph: „aus emsenhuber.net wurde schon wieder bf.lan — das müssen wir ein für alle mal aus allen
|
||||
Geräten rausprügeln und in Nautobot festhalten."
|
||||
|
||||
**Ziel:** genau **ein** interner Namensraum `emsenhuber.net` (Split-Horizon `.36/.37 → .40`). `.bf.lan`
|
||||
und `.bf.emsenhuber.net` werden entfernt; Sollzustand in Nautobot dokumentiert.
|
||||
|
||||
**Scope (Reihenfolge = eigene Session):**
|
||||
1. **Bestandsaufnahme** aller Fundstellen: Core `/ip dns static` (`*.bf.lan`), DHCP-Option
|
||||
`domain`/Search-Domain je Netz, Caddyfile-Aliase (`*.bf.emsenhuber.net`), AdGuard-Rewrites `.36/.37`,
|
||||
stale `.16/.17`, Geräte-`identity`.
|
||||
2. **Entscheidung Zielschema** (nur `emsenhuber.net`, ggf. `bf.emsenhuber.net` als *einzige* interne
|
||||
Zone — Christoph-Entscheid) und Migrationsreihenfolge ohne DNS-Loch.
|
||||
3. **Umsetzen:** Core-DNS + DHCP + Caddyfile angleichen; stale `.16/.17` klären/abbauen.
|
||||
4. **Nautobot:** interne Namen/Records als Sollzustand erfassen (Bezug TP37 Datenmodell).
|
||||
|
||||
**Abgrenzung:** kein CF-Public-DNS-Umbau (Zone `emsenhuber.net` öffentlich bleibt); kein Resolver-Swap
|
||||
(`.36/.37` bleiben); `.1`-als-DNS-Reste auf Clients sind separat/tolerierbar (User: „bis jetzt kein
|
||||
Problem"). **Abh.:** TP37 (Nautobot-Datenmodell) für Punkt 4; sonst nichts Offenes.
|
||||
|
||||
#### ✅ Bestandsaufnahme LIVE (2026-09-02) — Drift hat 80 % schon erledigt
|
||||
Gegen die Geräte gemessen (MikroMCP + dig), nicht aus dem Handoff:
|
||||
|
||||
| Fundstelle | Handoff 09-01 | Live 09-02 |
|
||||
|---|---|---|
|
||||
| Core `/ip dns static` | 11× `*.bf.lan` | ✅ **0× `.bf.lan`** — 10× `*.bf.emsenhuber.net` (deckt sich mit GC-Template Z.284–293) |
|
||||
| DHCP `domain` (7 Netze) | „prüfen" | `emsenhuber.net` (GC-Template Z.133 = gleich ⇒ **keine Drift**), DNS `.36/.37` |
|
||||
| `.36/.37` (Soll) | aktiv | `vw.emsenhuber.net→.40` ✅ · `macmini.bf.emsenhuber.net→.20.167` ✅ · **`macmini.emsenhuber.net→leer`** ❌ |
|
||||
| Caddyfile | `*.bf.emsenhuber.net`-Aliase | unverändert, **konsistent** mit Core-Static |
|
||||
| `.16`/`.17` | tot | laufen (:53), liefern totes VLAN1; **kein Core-Objekt** (Firewall/NAT/DNS-Upstream/Addr-List) hängt an `.16` |
|
||||
|
||||
**Kernkonflikt:** DHCP verteilt `emsenhuber.net` (bare), Records leben unter `bf.emsenhuber.net` ⇒ bare `macmini` löst nicht.
|
||||
|
||||
#### ✅ Entscheidungen (User, 2026-09-02)
|
||||
1. **Zielschema = `bf.emsenhuber.net`** (der wenig-Arbeit-Weg): DHCP-domain → `bf.emsenhuber.net`, dann
|
||||
löst `macmini` bare korrekt; Core-Static + Caddyfile bleiben (tragen schon `.bf.`). Öffentliche Zone
|
||||
`emsenhuber.net` bleibt getrennt.
|
||||
2. **`.16` (adguard_bf1) abbauen**, **`.17` (adguard_fm2 = Standort FM) NICHT anfassen.**
|
||||
|
||||
#### ✅ Umsetzung DURCH (2026-09-02)
|
||||
- **(A) DHCP-domain `emsenhuber.net → bf.emsenhuber.net` über GC ✅** — kein Direkt-Write:
|
||||
`mikrotik_routeros.j2` Z.133 gehoben → `push-gc-template.py` (Commit `7a4068c4`, **Nebenbefund:** das
|
||||
Remote-Template hing dem lokalen hinterher — es trug noch `*.bf.lan`+`router.lan`, obwohl Gerät+lokal
|
||||
längst `.bf.emsenhuber.net` fuhren; der Push hat das GC-Repo an den Live-Stand angeglichen) →
|
||||
GitRepo-Sync (SUCCESS) → manueller ConfigPlan **`tp42-dhcp-domain`** (`set [find] domain=…`, weil
|
||||
`add` das Netz doppelt anlegen würde) → Deploy an **crs326-core** → Live **7/7 = bf.emsenhuber.net**,
|
||||
Compliance **140/140, keine Drifts**. Der Job steht dauerhaft in `nautobot/gc-configplan.py`.
|
||||
- **(B) `.16`-Teardown ✅** — `adguard_bf1` lag im geteilten Portainer-Stack **195 `adguard`** (Docker-LXC
|
||||
`.126`, **ep2** — *nicht* ep14) **zusammen mit `adguard_fm2` (`.17`, Standort FM!)**. Deshalb **nicht**
|
||||
Stack löschen, sondern compose auf nur `.17` getrimmt + Stack redeployt (Prune): `.16`-Container weg,
|
||||
`.16:53` tot; **`.17` läuft** (⚠️ ~40 s mit-neugestartet durch den Redeploy — kurzer FM-DNS-Blip,
|
||||
danach sauber). Rollback-compose gesichert. 🧹 Daten-Dirs `/opt/docker/adguard_bf1/*` bleiben als
|
||||
harmlose Leichen auf dem LXC.
|
||||
- **(C) Nautobot-Soll** (Scope-Punkt 4) bleibt an **TP37** gekoppelt (Datenmodell), separat — kein Blocker.
|
||||
|
||||
**Status:** ✅ **Namensraum vereinheitlicht (2026-09-02)** — ein interner Suffix `bf.emsenhuber.net`,
|
||||
`.bf.lan` raus, `.16` abgebaut, Compliance 140/140. Offen nur der TP37-gekoppelte Nautobot-Doku-Teil.
|
||||
Handoff: [`docs/handoff-20260901-tp42-naming.md`](handoff-20260901-tp42-naming.md).
|
||||
|
||||
@@ -25,263 +25,24 @@ IP-Blöcke: `.1–10` Router/Gateways · `.11–20` Switches/APs. **GW je VLAN =
|
||||
Mgmt (VLAN99, Ist 2026-08-16): core `.99.1` · branch `.99.2` · ap1 `.99.11` · ap2 `.99.12`.
|
||||
*(Historisch, überholt: „ap1=.1, ap2=.2 · ALLNET=.11, Omada=.12" — aus der Zeit vor dem Core-Cutover.)*
|
||||
|
||||
## Ist-Stand (Kurz)
|
||||
## Status & Index → Gitea-Board (SSoT seit 2026-09-07, TP36-Cutover)
|
||||
|
||||
**Stand 2026-08-31 — live gegen die Geräte geprüft (MikroMCP/REST/SSH), nicht aus der Doku abgeschrieben.**
|
||||
**Compliance am 2026-08-31 nach vollem Refresh (Backup→Intended→Compliance) gelesen: 128/135.**
|
||||
*(Die Fassung vom 2026-08-16 stand bis zum 18. hier und war an vier Stellen überholt. Wer diesen Block
|
||||
liest, liest ihn als Erstes: er wird bei jeder Änderung mitgezogen, nicht nur die TP-Abschnitte.)*
|
||||
- 🆕 **MCP-Bestand 2026-08-28 korrigiert:** **9 MCPs identisch** in `~/.claude.json` und `~/.config/opencode/opencode.jsonc` (vorher Asymmetrie 7 vs. 11 — `portainer-mcp`/`shelly-mcp` raus, `gitea-mcp`/`n8n-mcp` rein). **Mac mini = n8n-Host, NICHT zentraler MCP-Host** (Performance-Restriktion); zentraler MCP-Host = **DS923** (`nas-bf`, Portainer Endpoint 14). Inventur-Stand `mcp/INVENTORY.md` + Policy `docs/mcp-host-policy.md`.
|
||||
- 🆕 **MCP-Migration FQDN→IP (2026-08-29, TP35 Schicht 1):** `gitea-mcp` und `n8n-mcp` in `~/.config/opencode/opencode.jsonc` von CF-FQDN auf LAN-IP umgestellt — `gitea-mcp` → `http://10.40.20.167:3000/mcp` (macmini, **ohne** Bearer, intern), `n8n-mcp` → `http://10.40.20.167:3001/mcp` (mit `Bearer {env:N8N_MCP_BEARER}`). **Befund dabei:** der Handoff 1.2 nannte für gitea-mcp die falsche IP `.157:3000` (das ist die Gitea-Web-UI, `400 Invalid CSRF`); der echte gitea-mcp läuft auf `.167:3000` (`serverInfo: gitea-mcp 0.0.10`). `cloudflare`-MCP bleibt auf dem offiziellen FQDN (User-Direktive).
|
||||
- 🆕 **TP16.3 §2/§3 durchgezogen (2026-08-31, Vor-Ort):** je ein `cloudflared`-Container auf
|
||||
**ap1/ap2/ap3**, `bf-public` **healthy mit 12 Connectoren** — der Tunnel hat damit zum ersten Mal
|
||||
überhaupt Connectoren. 🔴 **Zwei Runbook-Fehler dabei aufgedeckt:** die Flash-Rechnung war um Faktor
|
||||
2,5 zu optimistisch (entpacktes cloudflared = **69,5 MiB**, nicht 28 MB ⇒ das offizielle Image passt
|
||||
auf keinen der drei APs; Ersatz ist ein selbst gebautes `FROM scratch`-Image mit 35,3 MiB, Binary-SHA
|
||||
`e93824f6…` gepinnt), und `/container/envs` heisst `list=`, nicht `name=`.
|
||||
🔴 **Offen: Compliance 128/135.** §3.4 verlangt Direkt-Writes für `ip address`/`nat`, die unter
|
||||
GC-Kontrolle stehen ⇒ **sechs neue `extra`-Drifts** (zwei je AP), inhaltlich richtig, aber nicht im
|
||||
Soll. Braucht eine Entscheidung (ins Template heben), **kein Re-Baseline**. Details im TP16.3-Abschnitt.
|
||||
- 🆕 **TP37 angelegt (2026-08-30, User-Okay):** Nautobot soll durchgehende Netzwerkdoku werden, erster
|
||||
Anwendungsfall die CF-Connectoren. 🔴 **Befund dabei, live gegen die API:** Nautobot kennt heute
|
||||
**nur die 8 Netzgeräte** (4 aktiv, 4 decommissioned) — `ipam.Service`, `CustomField`, `Relationship`,
|
||||
`VirtualMachine` und `Tag` sind **alle 0**, installiert ist nur `golden-config`. Kein Host, kein
|
||||
Container, kein Dienst ist erfasst. **TP37 ist damit zuerst eine Datenmodell-Frage** und liefert das
|
||||
Fundament, das **TP34** (Caddyfile via GC) und **TP36** (SSoT für diese Datei) ebenfalls brauchen —
|
||||
Reihenfolge: **TP37 vor TP34**.
|
||||
- 🆕 **CF-Public-Strang eingedampft (2026-08-30, TP16.3 grosser Schnitt):** **12 Hostnames** aus Ingress
|
||||
**und** DNS entfernt — `pve`/`portainer`/`pve-mcp`/`ha-mcp`/`ds-bf`/`ccu`/`iobroker`/`z2m25`/`pbs`
|
||||
plus die drei CF-Access-SSH-Ziele. Ingress: `bf-mm` 6→4, `bf-nas` 6→3, `bf-pve` 9→2. **Öffentlich
|
||||
bleiben nur `vw`/`hass`/`n8n`/`gitea`** (weiterhin HTTP 200). Intern unverändert über AdGuard→Caddy
|
||||
(9× HTTP 200). ✅ **Nachtrag 2026-08-30 (F1 durch): `gitea-mcp`/`n8n-mcp` sind jetzt AUCH
|
||||
geschnitten** — damit **14 Hostnames** gesamt und `bf-mm` **4→2** (nur noch `n8n` + Catch-all).
|
||||
Möglich wurde das, weil zuvor **12 MCP-Client-Configs** auf LAN-IP migriert wurden (nicht 10 wie
|
||||
geschätzt: zwei Worktree-Kopien in `bf-network-r6{,.opencode}` kamen dazu). 🔴 **`bf-public` hat weiterhin 0 Connectoren** — er gehört
|
||||
laut Entscheid auf **ap1/ap2**, dort fehlen aber `container`-Paket **und** `device-mode container=yes`
|
||||
(physische Bestätigung nötig). Bis dahin stehen `bf-mm`/`bf-nas`/`bf-pve` mit **6 Containern**.
|
||||
Backups: `docs/cf-backup/*-20260830-vor-tp16.3-schnitt.json`.
|
||||
- 🆕 **TP16.3/TP31 Schritt 5 vorbereitet (2026-08-30):** Runbook für die Vor-Ort-Session geschrieben
|
||||
([`tp16.3-bf-public-ap-connector-runbook.md`](tp16.3-bf-public-ap-connector-runbook.md)), CF-Rollback-Snapshots
|
||||
unter `docs/cf-backup/*-20260830-vor-tp16.3-schnitt.json` **neu angelegt** (es gab sie vorher nicht).
|
||||
`docs/tp31-schritt5-runbook.md` ist damit **abgelöst** (read-only-Header): es kannte ap3 nicht,
|
||||
unterstellte einen Registry-Pull (`fetch: no` auf ap1/ap2) und enthielt eine **falsche**
|
||||
Firewall-Freigabe-Behauptung. **CF-Stand:** `bf-public` `inactive` / 0 Connectoren; die vier
|
||||
öffentlichen Namen laufen noch über bf-mm/bf-nas/bf-pve **an Caddy vorbei** direkt aufs Backend.
|
||||
- 🆕 **TP38 angelegt (2026-08-31):** OOB-Management — je ein untagged-VLAN99-Port auf beiden Switches.
|
||||
Auslöser: beim Core-Neustart war `crs326-branch` nicht erreichbar, weil sein Mgmt **ausschließlich**
|
||||
über den Core läuft (`vlan99` dort `tagged=ether1,ether24,bridge`, kein untagged-Member).
|
||||
🔴 **Nebenbefund mit eigenem Gewicht: `crs326-branch` hat gar keine `input`-Firewallregeln** — sein
|
||||
Schutz ist heute allein die Erreichbarkeit über den gehärteten Core. Das ist die Hauptauflage des TPs.
|
||||
- 🆕 **ROS-Upgrade 7.24.1 auf allen fünf (2026-08-31, User).** In Nautobot nachgezogen: **ap1** stand
|
||||
als einziges Gerät noch auf `7.24` (die anderen vier waren schon richtig) ⇒ auf `7.24.1` gesetzt.
|
||||
⚠️ **Korrektur (2026-08-31, nachträglich):** die dabei gesehene `wifi-security`-Drift auf
|
||||
`crs326-core` (`sec-main` `ft-over-ds=no` statt `yes`) hatte **nichts mit dem Upgrade zu tun** — sie
|
||||
ist **TP25 Fund E, Hebel 1**, um 08:09 bewusst gesetzt (Core-Upgrade war erst 14:36) und als
|
||||
**offene Transaktion `TP25-fund-e-ft-over-ds`** geführt (Scope `wifi-security`, Ablauf 2026-09-03).
|
||||
**Die 134/135 sind Absicht**, nicht Schaden: grün machen würde den laufenden Versuch unsichtbar
|
||||
machen, und `gc-transaktion.py` verweigert den Commit ohnehin, solange der Scope driftet.
|
||||
🔑 **Lehre:** vor jeder Drift-Bewertung `nautobot/gc-transaktion.py status` lesen — Drift aus einem
|
||||
laufenden Versuch sieht identisch aus wie ein Versehen, und genau dafür gibt es das Werkzeug.
|
||||
- 🆕 **TP16.3 §1-Blocker remote erledigt (2026-08-31):** Ingress von `bf-public` auf
|
||||
`https://10.40.20.40:443` + `originServerName`; Firewall-Freigabe `vlan99 → vlan20:443` **über
|
||||
Nautobot GC** (Plan `Completed`, Re-Baseline `ingest-core-firewall.py --apply`, danach
|
||||
**135/135 compliant / 0 Drifts**); `ROUTER_AP3_PASS` in `~/.secrets`. **Offen bleibt nur die
|
||||
Vor-Ort-Session** (§2/§3: `container.npk`, `device-mode`, Container) und danach Flip + Abbau.
|
||||
- 🆕 **Globale Verhaltensregeln konsolidiert (2026-08-29, TP35 Schicht 3):** `~/.config/opencode/AGENTS.md` ist jetzt die **SSoT** für globale Verhaltensregeln (Secrets, VLAN-Schema, 5 Lessons, SoC, Übergabe-Mechanik, Mid-Action-Checkpoint, Commit-Hinweis, Backup-Guard). `~/.claude/CLAUDE.md` hält denselben Block als Claude-Code-Spiegelung mit Verweis auf die SSoT. opencode liest AGENTS.md mit Vorrang vor `~/.claude/CLAUDE.md`.
|
||||
|
||||
- **Alle fünf MikroTik laufen auf RouterOS `7.24.1`** (🆕 **Angleichung am 2026-08-31 von Christoph
|
||||
selbst durchgezogen, TP27 damit erledigt** — ap2 08:56, core 14:36, ap1 14:50, branch 14:52;
|
||||
ap3 kam bereits so. RouterBOOT jeweils = `upgrade-firmware` = `7.24.1`, live gegengelesen).
|
||||
Vorher: vier auf 7.24 (08-17), nur ap3 auf 7.24.1. Neu in der Flotte **`ap3`**
|
||||
(cAP ax `cAPGi-5HaxD2HaxD`, **`10.40.99.13`**, Uplink core `ether21`).
|
||||
✅ **Folge für TP16.3:** die versionsgebundene `container.npk` ist damit **eine** Datei für alle drei
|
||||
APs (alle `arm64`) — die Zwei-Dateien-Regel vom 08-30 war rein versionsbedingt und ist erledigt.
|
||||
*(Hier stand bis 08-29 „Alle vier MikroTik … 7.24" — durch ap3 und das Upgrade zweifach überholt.)*
|
||||
- **L3 + WAN-Edge = `crs326-core`** (CRS326-24G-2S+, Technik UG): Routing, DHCP (7 Server,
|
||||
54 Reservierungen), DNS, NAT, **NTP-Server für den Standort** und der WG-Hub (TP10, Peers `fm`/`dw`)
|
||||
laufen hier. Mgmt-SVI **`10.40.99.1`** (vlan99), Gateway `.1` je VLAN. **WAN = `vlan100`** — DHCP-Client
|
||||
hält die öffentliche Liwest-IP **`90.146.33.177/24`** direkt vom Arris (Bridge-Mode) → kein Double-NAT.
|
||||
**DNS-Upstream = DoH zum CF-Gateway mit `verify-doh-cert=yes`** (TP23 Stufe 1 ✅ 08-18);
|
||||
`servers=1.1.1.1` steht nur noch als Bootstrap für den DoH-Hostnamen.
|
||||
- 🔥 **Die Firewall ist deny-by-default — in BEIDEN Ketten** (TP5 E3/E4 ✅ 08-18). `TP10-seal-lan` ist
|
||||
`disabled`; Mgmt-Input kommt nur noch aus VLAN10, von HA (`8728`), von Nautobot (`22`) und über
|
||||
`cf-mesh`. Ein neuer Dienst über eine VLAN-Grenze braucht ab jetzt eine explizite Regel.
|
||||
- **L2-Branch = `crs326-branch`** (Technik OG): reiner L2-Switch, Mgmt **`10.40.99.2`**,
|
||||
Uplink `ether1` → core `ether8`.
|
||||
- **WLAN = CAPsMAN auf dem Core** (TP28 ✅ 08-17, GC-Modell nachgezogen 08-18): ap1 **`10.40.99.11`**
|
||||
(an core `ether15`), ap2 **`10.40.99.12`** (an branch `ether24`), beide **reine CAPs** —
|
||||
`cap enabled=yes`, `discovery-interfaces=vlan99`. Die APs halten **keine eigene WLAN-Config** mehr;
|
||||
Kanäle, SSIDs, Security und Steering kommen vom Manager. 802.11r/k/v aktiv, `ft-over-ds=yes`.
|
||||
🆕 **Dritter AP `ap3` (cAP ax) ✅ LIVE seit 2026-08-30** (TP28 dafür wieder geöffnet):
|
||||
`10.40.99.13`, Uplink `ether1` → **core `ether21`** (Trunk), reiner CAP, **RouterOS 7.24.1**
|
||||
(🆕 **seit 2026-08-31 die ganze Flotte** — die frühere Versionsdifferenz ist aufgelöst). Kanäle
|
||||
**`5180/ax/Ce/I`** + **`2437/ax`** (ch6) nach dem TP25-Plan vom 2026-08-24, am Gerät nachgemessen.
|
||||
🔴 **ap1 ist funkstill** — es steht bis zu seinem Umzug ans Sideboard direkt neben ap3 und würde
|
||||
auf 5180 kollidieren; es hat deshalb bewusst **keine Provisioning-Regel** am Manager, bleibt aber
|
||||
erreichbar. Beim Umzug: ap1 → `5260/Ce` (Band B, DFS, **Frequenz-Liste statt Einzelwert**),
|
||||
ap2 → `5300/Ce`, Uplink ap1 → `core ether3`.
|
||||
**Compliance jetzt 130/130 / 0 Drifts über 5 Geräte** (vorher 104/104 über 4).
|
||||
- **SSDP-Relay** (TP7.1, **nachgebessert 08-25**): LXC **108 `mcast-relay`** auf pve, zweibeinig
|
||||
`10.40.10.21` (VLAN10) + `10.40.40.21` (VLAN40) — dafür trägt `core ether13` beide VLANs; mDNS macht
|
||||
weiterhin der Core. **Läuft seit 08-25 ohne `--ssdpUnicastAddr`** — die Flagge verwarf die M-SEARCH
|
||||
der App auf dem Weg nach VLAN40 (Messung: **0 Pakete `via eth1` gegen 308 `via eth0`** in 20 min,
|
||||
**0×** `Received SSDP Unicast` im ganzen Journal seit 08-18). Der Rückweg läuft jetzt **nativ geroutet**
|
||||
über die längst offene Regel `TP5: MEDIA->MAIN`; nachgemessen kommen `HTTP/1.1 200 OK` von
|
||||
`10.40.40.193/.195` an beiden MacBook-Beinen an. Unit liegt im Repo: **`mcast-relay/multicast-relay.service`**,
|
||||
Details als Gotcha in `CLAUDE.md`. ⚠️ **Der Fall hatte zwei unabhängige Ursachen** — nach der
|
||||
Relay-Reparatur suchte die **App** immer noch nicht (macOS-Local-Network-Gate stand auf „an" und
|
||||
griff nicht; Fix war Schalter aus/ein + Neustart, User-bestätigt 08-25). **Beide sind erledigt.**
|
||||
- **Reverse Proxy = `caddy-bf1`** (LXC 130 auf pve, **`10.40.20.40`**, TP31 ✅ Schritt 1–3 seit
|
||||
2026-08-25, **`hass` 400 behoben 2026-08-26, Split-Horizon seit 2026-08-26**): Caddy 2.11.4,
|
||||
**16 Sites** (4 public, 12 intern mit `.bf.`-Suffix), Zertifikate ausschliesslich
|
||||
per **DNS-01** mit einem eng geschnittenen `Zone:DNS:Edit`-Token (`CF_DNS_API_TOKEN`, **nicht** das
|
||||
account-weite). Abnahme über den Host-Header von einem zweiten Host: 11× 200, `nautobot` 302.
|
||||
Offen: **Schritt 5–6** (Connector für `bf-public`, CNAME-Flip, Abbau der sechs Container) —
|
||||
**Runbook steht: [`tp16.3-bf-public-ap-connector-runbook.md`](tp16.3-bf-public-ap-connector-runbook.md)**,
|
||||
Vor-Ort-Session an ap1/ap2/ap3. ✅ **Die drei §1-Blocker sind am 2026-08-31 remote erledigt** —
|
||||
**(a)** Ingress auf `https://10.40.20.40:443` + `originServerName` je Regel umgestellt (die alte
|
||||
`:80`-Zeile hätte über CF eine Redirect-Schleife gebaut, weil Caddy dort 308 auf https antwortet);
|
||||
**(b)** Freigabe `vlan99 → vlan20:443` **über Nautobot GC** deployt (`ip-firewall-filter` steht unter
|
||||
Drift-Kontrolle, TP26 ⇒ kein Direkt-Write), Position vor `TP5: log-only` verifiziert, **135/135
|
||||
compliant, 0 Drifts**; **(c)** `ROUTER_AP3_PASS` in `~/.secrets` nachgetragen (REST-Auth 200).
|
||||
⇒ **Vor Ort startet die Arbeit bei §2/§3** (Pakete, `device-mode`, Container).
|
||||
- **DNS/Resolver = AdGuard-Paar `agh-bf1`/`agh-bf2`** (LXC 110/111 auf pve, **`10.40.20.36`/`.37`**,
|
||||
TP23 Stufe 2 + TP31 Schritt 4 ✅ seit 2026-08-26): Upstream DoH zum CF-Gateway, conditional
|
||||
`[/bf.emsenhuber.net/] → 10.40.20.1`, 47 Rewrites (16 Service → Caddy `.20.40` + 10 Host-Namen
|
||||
mit `.bf.`-Suffix + alte suffixlose parallel). DHCP liefert `.36`/`.37` als DNS in allen 7 VLANs
|
||||
(`domain=emsenhuber.net`), Firewall forward UDP+TCP/53 auf beide. Der Core-Resolver (`10.40.X.1`)
|
||||
bleibt als Bootstrap unverändert (DoH, `allow-remote-requests=yes`, `mdns-repeat-ifaces`).
|
||||
- **Ausgebaut / gelöscht:** ALLNET-`sw1` und Omada-`sw2` sind **physisch weg** (2026-08-08 bzw. 2026-07-23,
|
||||
in Nautobot *Decommissioned*); Omada-Controller + `omada-mcp` gelöscht (2026-07-16); FritzBox 6660 raus
|
||||
seit 2026-07-01 (Liwest-Tausch auf Arris). **VLAN1 ist leer** (`/ip arp` auf `bridge` = 0 Einträge,
|
||||
08-18) — TP19 ist geschlossen; `cudy1` hängt stromlos an core `ether11`, physischer Ausbau ist hands-on.
|
||||
- 🆕 **WLAN-Logging persistent seit 2026-08-30 (TP25 Fund E):** `wireless` + `caps` gehen vom Core
|
||||
in den TP5-Kollektor (`10.40.20.18:514`); `/system logging` steht unter der **27. ComplianceRule**
|
||||
`system-logging`. Vorher nur Ringpuffer → ein seit Wochen gemeldeter iPhone-Abbruch war rückwirkend
|
||||
nicht diagnostizierbar.
|
||||
- 🔴 **TP25 Fund E — Hebel 1 ist GESCHEITERT (Stand 2026-08-31 nachmittags):** `sec-main` steht am
|
||||
Core auf **`ft=yes ft-over-ds=no`** (seit 08:09), aber das Symptom blieb: **124× `reauthenticating`
|
||||
nach dem Eingriff** und **zwei von Christoph erlebte Ausfälle** — 13:16 (Videocall bricht ab,
|
||||
7 min ohne WLAN) und 14:23 (5,5 min, nur durch WLAN-Toggle beendet). Stundenvergleich auf
|
||||
gleicher Firmware: **07:00–08:00 = 79 · 14:00–15:00 = 70**. Erfolgskriterium war „~0" ⇒ nicht
|
||||
eingetreten. Gewertet wird bewusst nur **08:09–14:36** (danach kommt das TP27-Upgrade als zweite
|
||||
Variable dazu; Christoph-Entscheid: „Vormittag als Ergebnis werten").
|
||||
⇒ Transaktion **`TP25-fund-e-ft-over-ds` bleibt OFFEN** (Ablauf **2026-09-03**), **Compliance
|
||||
weiter bewusst 134/135**; Rollback oder Commit ist eine Entscheidung, kein Aufräumen.
|
||||
Geräte-Backup `pre-tp25-funde-ftoverds.backup` liegt auf dem Core.
|
||||
**Nächste Entscheidung:** Hebel 2 (`ft=no`) **oder** `authentication-types=wpa2-psk,wpa3-psk` —
|
||||
`sec-main` ist auch die einzige SSID ohne `wpa2-psk`, und `association rejected, no cached PMK`
|
||||
(157× am 31.08., 0× am 30.08.) ist eine SAE/PMKSA-Meldung. **Vorher prüfen, ob 7.24.1 auf dem
|
||||
Manager das Verhalten schon verändert hat** — zwischen 14:37 und 15:12 stand nur **1**
|
||||
`reauthenticating` im Log, keines vom iPhone (35 min = noch keine Aussage).
|
||||
Details: [`handoff-20260831-tp27-upgrade-und-hebel1-befund.md`](handoff-20260831-tp27-upgrade-und-hebel1-befund.md).
|
||||
- ⚠️ **Messfalle, die diese Session fast erwischt hat:** die 13 CAP-`joined`/`activity timeout` vom
|
||||
31.08. sahen nach CAPWAP-Instabilität aus — es waren die **Reboots des TP27-Upgrades**. Und die
|
||||
**`cap-wifiN`-Karte hat sich an einem Tag zweimal verschoben** (08:09, 14:36), womit die im
|
||||
Vorgänger-Handoff festgehaltene Tabelle nach sechs Stunden falsch war. Interface-Namen in
|
||||
Logzeilen sind ohne zeitnahen Karten-Snapshot **nicht zuschreibbar**.
|
||||
- **Kontrolle / Governance:** MikroMCP für Reads/Debug (alle 5 Geräte in der Registry),
|
||||
**Config-Änderungen ausschließlich über Nautobot Golden Config** (TP21/TP22 — Deploy-Pipeline scharf,
|
||||
**135/135 Compliance-Checks grün, 0 Drifts** bei **27 Rules × 5 Geräten** (Stand 2026-08-30;
|
||||
**seit 2026-08-31 vorübergehend 134/135 — der eine Drift ist die offene Transaktion
|
||||
`TP25-fund-e-ft-over-ds`, s. oben, kein Fehler**) — live gegen die API
|
||||
geprüft am **2026-08-23**; zuletzt dazugekommen: **`wifi-access-list`** (08-22), **`queue`**
|
||||
(08-23, TP6) und **`ip-firewall-mangle`** (08-23, TP6.1), s. TP22-Nachtrag im Archiv).
|
||||
*(Hier stand bis zum 08-23 „100/100 bei 25 Rules" — eine Zählung, die TP6.1 am selben Tag überholt
|
||||
hat. Die Merkregel gilt: der Ist-Stand-Block wird bei jeder Änderung mitgezogen, nicht nur der TP.)*
|
||||
|
||||
<details><summary>📜 Historische Fassung (Stand bis 2026-08-08, Topologie <b>vor</b> dem Core-Cutover — bewusst erhalten, nicht als Ist lesen)</summary>
|
||||
|
||||
> ALLNET-Core `.11` (FW2.2.1, VLANs 10/20/30/40/50/90/99/100; GE1/GE2/GE8 Trunk; **TP1 ✅ 2026-06-15**). Omada-Switch `.12` (adopted, **TP2 ✅ 2026-06-15**; Trunk-ALL auf P1+P2, Access-Profile auf P3-P8; Profile noch PVID=1 bis Omada-PVID-Fix).
|
||||
> Omada-Controller **`.175`** (DS923/macvlan, mbentley 6.2, 🟢 live). omada-mcp **`.176`** (pve-LXC, StreamableHTTP, 🟢 live, 84 read-Tools; Controller-API v2 intern via christoph@emsenhuber.com).
|
||||
> 2× hAP ax² (7.23.1): ap1 `.1` (ALLNET P1) — **TP4 ✅ 2026-07-01: Router + WAN-Edge** (VLAN-Subinterfaces, DHCP, DNS, NAT, Public-Edge). ap2 `.2` (Omada P2 — Trunk).
|
||||
> **Edge-Cutover ✅ 2026-07-01:** FB6660 physisch entfernt (Liwest-Kabelmodemtausch, kein Zurück), Arris-Kabelmodem im Bridge-Mode; WAN = `sw1 gi16 Access VLAN100 → gi15 Trunk → ap1 ether2 → vlan100 auf bridge` (**NICHT** ether1); ap1 hält Public-IP direkt (Liwest, kein CGNAT), Double-NAT weg. Telefonie war auf der FB und wird nicht weitergeführt. Vorarbeit: TP10-Kern durch (2026-06-27, WG-Hub live) → Bridge-Gate vorher gelöst. Runbook: `routeros/wan-cutover-runbook.md`.
|
||||
> Kontrolle: MikroMCP (MikroTik) live · ALLNET = Klickanleitungen · Omada → Controller + omada-mcp 🟢.
|
||||
|
||||
</details>
|
||||
|
||||
**Nächster Schritt (Stand 2026-08-30): Vor-Ort-Session ap1/ap2** — sie ist der einzige Weg, den
|
||||
Public-Strang auf `bf-public` zu heben und die drei Alt-Tunnel samt sechs Containern abzubauen
|
||||
(TP16.3 Follow-up F2). ✅ **F1 ist am 2026-08-30 durch** (12 Client-Configs auf LAN-IP, danach
|
||||
`gitea-mcp`/`n8n-mcp` aus Ingress+DNS geschnitten) — davor unabhängig machbar bleibt nur noch die
|
||||
**Announcement-Doku (TP35 Schicht 4)**, die den anderen Projekten die neuen MCP-URLs mitteilt.
|
||||
|
||||
**Vorherige Fassung (Stand 2026-08-28): drei Folge-Sessions parallel** (siehe `docs/handoff-20260828-mcp-bestand-und-performance.md`):
|
||||
> - ✅ **Session A** — `/projektstatus`-Skill global für opencode (TP35 Schicht 6). Funktionsbeweis erbracht 2026-08-28.
|
||||
> - 🔜 **Session B** — shelly-mcp-Container auf DS923 (`10.40.20.10`) deployen (live, ssh). Repo-Materialien committed (`mcp/shelly/{Dockerfile,BUILD.md,requirements.txt,.gitignore}`); `.env` und Tunnel-Secret lokal — kein MCP-Client (User-Direktive).
|
||||
> - 🔜 **Session C** — `caddy/cf-sync.py`-Drift-Check + Backup-Guard (`~/dev/.bin/backup-guard.sh`, TP35 Schicht 5).
|
||||
> 🧭 **Ist-Stand, kritischer Pfad und Quick-Index leben ab jetzt als Gitea-Issues**, nicht mehr in
|
||||
> dieser Datei: **[admin/bf-infra · Issues](https://gitea.emsenhuber.net/admin/bf-infra/issues)**.
|
||||
> **TP = Issue · Status = Label `status:*`** (todo/wip/paused/idea/concept/done/dropped) ·
|
||||
> **Gruppierung = Label `thema:*`**. Filtern über die Label-Chips der Issue-Liste, z.B.
|
||||
> [nur offene](https://gitea.emsenhuber.net/admin/bf-infra/issues?type=issue&state=open).
|
||||
>
|
||||
> 🆕 **Dazu seit 2026-08-30: TP16.3/TP31 Schritt 5 = Vor-Ort-Session** an ap1/ap2/**ap3**
|
||||
> ([Runbook](tp16.3-bf-public-ap-connector-runbook.md)). **Reihenfolge beachten:** die drei Blocker in
|
||||
> §1 sind **remote** zu erledigen, *bevor* jemand in den Keller geht — sonst steht man vor einem
|
||||
> Connector, der `healthy` meldet, während die Seite eine Redirect-Schleife dreht.
|
||||
> **Diese Datei führt nur noch die per-TP-Prosa** — die `### TPnn`-Abschnitte unten; Abgeschlossenes im
|
||||
> **[Archiv](teilprojekte-archiv.md)**. **Live-Gerätedaten** (Compliance-Zahl, RouterOS-Version …) kommen
|
||||
> aus **Nautobot**, nicht von hier. Sync-Werkzeug Datei/Archiv → Gitea (idempotent, Dry-Run default):
|
||||
> `bin/gitea-tp-sync.py`.
|
||||
>
|
||||
> 🆕 **Strukturelle Folge = TP36:** SSoT für `teilprojekte.md`-Live-Daten via Nautobot (eigene Session, nicht heute). Befund 2026-08-28: manuell gepflegte Datei verliert gegen die Realität, sobald sie lang wird. Quickref-Index, TP-Abschnitt und Ist-Stand-Block müssen bei jedem Edit mitgezogen werden — keine schlägt die andere. **Merkregel im Lessons-Block.**
|
||||
> *(TP36-Cutover 2026-09-07: die frühere Quick-Index-Tabelle und der chronologische „Ist-Stand (Kurz)"-Block
|
||||
> sind aus dieser Datei entfernt, damit TP-Branches nicht mehr auf der Steuerungs-Doku kollidieren — Status-
|
||||
> Updates gehen nach Gitea statt in diese Datei. Die alte Ist-Stand-Historie steht in der Git-Historie.)*
|
||||
|
||||
> 🆕 **Neu am 2026-08-24/25:** [TP31](#tp31) löst **TP16** und **TP16.2** ab und dampft cloudflared
|
||||
> von **sechs Containern auf einen** ein; [TP32](#tp32) gibt die Nummern- und Adress-Systematik vor
|
||||
> (und hat nebenbei die **falsche Startreihenfolge auf pve repariert** — HA startete vor seiner
|
||||
> Datenbank). **TP16 ✅, TP25 ✅ und TP16.3 (Pilot) ✅** sind am 24./25. durchgezogen worden.
|
||||
|
||||
**Vorherige Fassung (Stand 2026-08-23): Christoph entscheidet — der kritische Pfad ist LEER.**
|
||||
> 🎯 **Das Projekt ist in seinem Kern fertig.** deny-by-default steht (TP5), Golden Config steht und
|
||||
> meldet **104/104 compliant bei 0 Drifts** (live geprüft 2026-08-23), WLAN steht über CAPsMAN auf dem
|
||||
> Core (TP28), VLAN1 ist leer (TP19) — und **TP6 ist beantwortet statt offengelassen**: CAKE gebaut,
|
||||
> gemessen, wieder ausgebaut. **Nichts blockiert mehr etwas.**
|
||||
> 🟢 **Was zuletzt wirklich etwas gebracht hat, war TP6.1** (2026-08-23): nicht Shapen, sondern
|
||||
> **Klassentrennung** — NAS-Bulk `priority=8` gegen interaktiv `priority=1` drückt dieselbe Strecke
|
||||
> unter derselben Sättigung von **40,8 auf 11,0 ms (−73 %)**. Die zuerst notierte DOCSIS-Erklärung aus
|
||||
> TP6 ist damit **widerlegt**; der Fehler lag in der Messmethode (Last und Messung vom selben Host).
|
||||
> 📋 **Offen und ohne Blockadewirkung:** **TP25** (Fund F = 5:05-Takt bei IoT, plus die Entscheidung
|
||||
> „5 GHz auf 20 MHz") · **TP16** (CF-Tunnel-HA degradiert, vier tote Alt-Tunnel) · **TP16.2/16.3** ·
|
||||
> **TP23 Stufe 2** · **TP24** (DC-USV) · **TP13/TP14.4** (beide mit fertigem Runbook) ·
|
||||
> ❌ **TP17.1 VERWORFEN 2026-08-23** (Zigbee-Weg bewiesen, Ziel damit nicht erreichbar — das Gerät
|
||||
> bleibt WLAN-Client; `s9` zurückgebaut) · ✅ **TP17.3 ERLEDIGT** (Ursache **`eco_mode`** bewiesen;
|
||||
> `s23` + `s26` repariert; **`eco_mode` flottenweit aus**, 22/22 außer `s24`) ·
|
||||
> ➡️ **TP17.2 ist am 2026-08-24 in TP30 aufgegangen** (Shelly-Gerätepasswort = Erstvergabe eines
|
||||
> Credentials; TP30 ist das Sammelbecken dafür) ·
|
||||
> 🔑 **Alle Passwort-/Token-Rotationen sind seit 2026-08-24 TP30** (Sammel-TP) — **bewusst
|
||||
> gebündelt gegen Projektende**, User-Entscheid. Damit ist die ältere Einreihung „hinter TP17.1"
|
||||
> gegenstandslos (TP17.1 ist verworfen). **Etappe 1 — die Service-Accounts — ist durch;**
|
||||
> das `admin`-Passwort selbst ist **nicht rotiert** und bleibt es bis dahin bewusst.
|
||||
> 📌 **Einstieg für die nächste Session:
|
||||
> [`handoff-20260825-agh-dns-cutover.md`](handoff-20260825-agh-dns-cutover.md)** — AdGuard als
|
||||
> Resolver + Split-Horizon (TP23 Stufe 2 ∥ TP31 Schritt 4). **Bewusst eigene Session:** der Schritt
|
||||
> verschiebt die DNS-Auflösung des ganzen Standorts in einen Container.
|
||||
> 📜 Älter: [`handoff-20260824-session.md`](handoff-20260824-session.md)
|
||||
> — ⚠️ dessen Empfehlung „Start bei der Passwort-Rotation Etappe 2" ist durch den TP30-Entscheid
|
||||
> **überholt**; der Rest der Übergabe gilt. Ältere Sitzungsvorschläge:
|
||||
> [`handoff-20260822-naechste-schritte.md`](handoff-20260822-naechste-schritte.md).
|
||||
> ✅ **`crs326-core` ist transaktionsfrei** (seit 2026-08-22, geprüft): ein gemeldeter Drift ist ab
|
||||
> jetzt **echt**, nicht beabsichtigt — `python3 nautobot/gc-transaktion.py status`.
|
||||
|
||||
<details><summary>📜 Vorherige Fassungen dieses Absatzes (2026-07-22 → 2026-08-21, bewusst erhalten)</summary>
|
||||
|
||||
> *Fassung 2026-08-21 abends (erledigt — TP25s Dead Spot ist am 08-22 repariert, TP6 am 08-23 geschlossen):*
|
||||
> **Nächster Schritt: TP25 — Steering-Test in den Schlafräumen.**
|
||||
> 📋 **Einstieg: [`handoff-tp25-session-20260821.md`](handoff-tp25-session-20260821.md)** — dort steht
|
||||
> der verifizierte Ist-Stand, die Messfallen und der nächste Test.
|
||||
> ✅ **`crs326-core` ist transaktionsfrei (2026-08-22).** `TEST-ether3-trunk-ap1-sideboard` und
|
||||
> `TEST-infra-ssid-matter-pairing` sind beide zurückgerollt und geschlossen; ap1 hängt wieder auf
|
||||
> `ether15`, `ether3` ist wieder untagged VLAN40. Ein gemeldeter Drift ist ab jetzt **echt**, nicht
|
||||
> beabsichtigt — `python3 nautobot/gc-transaktion.py status`.
|
||||
> 🆕 **TP29** (Anwesenheitserkennung fürs Energiesparen) ist als Idee angelegt, nicht auf dem Pfad.
|
||||
> 📌 **Die TP6-Prämisse ist am 2026-08-20/21 gemessen** (Runbook §5): formal Fall B (+28…+47 ms unter
|
||||
> Dauer-Upload), aber im Videocall **nicht wahrnehmbar** — kein einziger Problem-Klick über sechs
|
||||
> Lastphasen. Laut war stattdessen der Funk: **Sticky Client + Band-Ping-Pong, zwölf Wechsel in neun
|
||||
> Minuten**, je Wechsel bis zu 4 s ohne Durchsatz →
|
||||
> [`tp25-wlan-roaming-messung-20260820.md`](tp25-wlan-roaming-messung-20260820.md). Deshalb steht jetzt
|
||||
> **TP25 vor TP6**; TP6 bleibt offen und begründet, aber nachrangig.
|
||||
>
|
||||
> *Vorherige Fassung (Stand 2026-08-18, erledigt):*
|
||||
TP6 wird hier seit Monaten als „DAS Ziel" geführt, aber `docs/call-quality-diagnosis.md` hat den
|
||||
Bufferbloat 2026-06-16 bereits gemessen (**A/A+**, „CAKE wäre marginal, nicht deployt"). Die Messung
|
||||
stammt aus der FritzBox-Ära, der Edge ist seither getauscht — also **einmal gegen den heutigen Edge
|
||||
nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Nacht auf den 18. abgeschlossen worden (Etappe 3 + 4: deny-by-default in `forward` **und** `input`, MGMT isoliert, `seal-lan` abgeschaltet), TP23 Stufe 1 (DoH auf dem Core) ebenfalls. Nebenher offen, blockiert nichts: **TP25** (Signal-Boden + Re-Walk), **TP28-Rest** (die fünf `wifi-*`-Features vom AP-Scope auf den Core umhängen — die einzigen verbliebenen Compliance-Drifts), **TP7.1** (SSDP-Relay für die macOS-Sonos-App), **TP16.3**, **TP24**.
|
||||
> *Vorherige Fassung (Stand 2026-08-14, überholt): „TP5 — Deny-by-default am Ende von `forward`." Alles Davorliegende ist durch:* CRS326-Bring-up + L3-Umzug ap1→`crs326-core` (TP15/TP21.1 ✅ 2026-08-08), WLAN-Neuprovisionierung ohne CAPsMAN (TP3 ✅ 2026-08-08), Nautobot-Plattform + Fleet-Adoption + Deploy-Pipeline (TP21/TP22 ✅ 2026-08-13). Danach **TP6 (CAKE) = das Projektziel**. Kleine Follow-ups nebenher: DoH-Cloudflare auf core, DC-USV (**TP24**, seit 2026-08-16 eigener TP). ⚪ **Omada-PVID-Fix ist obsolet** (User-Entscheid 2026-07-22 — Omada spielt seit der TP15-Korrektur keine Rolle mehr im Netz, nie mehr aufgreifen).
|
||||
> *Vorherige Fassung (Stand 2026-07-22, erledigt): „TP15 CRS326-Bring-up als neuer L3-Core, danach WLAN-Neuprovisionierung ohne CAPsMAN; TP5 folgt nach TP21/CRS326-Adoption."*
|
||||
|
||||
</details>
|
||||
## Governance & genehmigte Ausnahmen (stehende Regeln — kein Status)
|
||||
|
||||
> 🎯 **Ziel: sauberes System „from scratch", keine Leichen/Altlasten.** Migrations-Session-Endstand = **VLAN1 + altes cudy-WLAN komplett weg** (VLAN1 nur noch Mgmt, `defconf`-Client-DHCP zurückgezogen, cudy-Uplinks aufs Ziel-Client-VLAN getaggt oder cudy abgebaut). **Unterpunkte/Aufräum-Liste bei Migration:** (a) die Interim-Härtung ap2 `wifi1/wifi2 frame-types=admit-only-vlan-tagged` (TP3.1, 2026-07-06) bleibt gültig — verschwindet automatisch mit VLAN1; (b) ~~`st-main rrm/wnm` = reines Roaming-Provisorium~~ → **kein Provisorium mehr (2026-08-13, TP3.3): Steering ist fester Bestandteil des Golden-Config-Templates + ComplianceFeature `wifi-steering`** — es war die Neuprovisionierung, die es stillschweigend verloren hatte; (c) ~~**cudy1 = verbleibender aktiver VLAN1-Leak**~~ → **ERLEDIGT (User-bestätigt + verifiziert 2026-08-14): cudy1 ist offline.** `core ether11` trägt **kein Link** (kein `R`-Flag), Nautobot-Status *Offline* (TP22 Schritt 5). Damit existiert kein aktiver VLAN1-Leak mehr; der Dual-DHCP-Race aus `project_vlan1_dhcp_incident` ist Historie. Der formale Teardown (Gerät ausbauen, Doku/Inventar) bleibt TP19.
|
||||
> ⚠️ **HW-Constraint hAP ax²:** 1 GB RAM, aber nur **128 MB Flash + KEIN USB** → **Container auf dem Router NICHT praktikabel**.
|
||||
@@ -306,39 +67,7 @@ nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Na
|
||||
> ~~**TP17.2** ↔ TP17~~ *(TP17.2 ist am 2026-08-24 in **TP30** aufgegangen und kein eigenes TP mehr)*
|
||||
> und **TP20.1** ↔ TP20).
|
||||
>
|
||||
> ### 📊 Quick-Index (nur dieser Block ist für den Statusbaum nˆtig — 1 Read)
|
||||
>
|
||||
> | # | Status | Kurztitel | Abschluss |
|
||||
> |---|---|---|---|
|
||||
> | TP5.1 | ⏸️ | DNS-Visibility Airfryer | — |
|
||||
> | TP8 | ⏸️ | Identity / 802.1X | — |
|
||||
> | TP11 | ⏸️ | Monitoring | — |
|
||||
> | TP12 | ⏸️ | IPv6 (3 Standorte) | — |
|
||||
> | TP12.1 | 🔜 | IPv6 ULA + v6-Firewall | — |
|
||||
> | TP13 | 🔜 | Botschafts-WLANs | — |
|
||||
> | TP14.4 | 🔜 | CF-Access-Token | — |
|
||||
> | TP16 | ✅ | CF-Tunnel HA wieder voll | 2026-08-24 |
|
||||
> | TP16.2 | 🔜 | Härtung bypass-Dienste | — |
|
||||
> | TP16.3 | ⏳ | cloudflared-Reduktion (14 Hostnames geschnitten 08-30, F1 durch; §1–§3 durch 08-31, `bf-public` healthy/12 — offen: Flip §5, Abbau §6) | — |
|
||||
> | TP17.1 | ❌ | Shelly Gen4 → Zigbee | 2026-08-23 |
|
||||
> | TP17.3 | ✅ | Shelly-Regression behoben | 2026-08-23 |
|
||||
> | TP18 | 🔜 | Garage-Objektspeicher | — |
|
||||
> | TP20.1 | 🔜 | Vaultwarden → Platform-PG | — |
|
||||
> | TP23 | ✅ | DNS-Policy (Stufe 1+2 ✅) | 2026-08-26 |
|
||||
> | TP24 | 🔜 | DC-USV | — |
|
||||
> | TP25 | 🔬 | WLAN-Stabilisierung (Kern ✅) — **Fund E offen, Hebel 1 `ft-over-ds=no` läuft, Messung bis 09-01** | 2026-08-31 |
|
||||
> | TP28 | ✅ | WLAN/CAPsMAN — dritter AP `ap3` (cAP ax) **live** | 2026-08-30 |
|
||||
> | TP29 | 💡 | Anwesenheitserkennung (Idee) | — |
|
||||
> | TP30 | 🔜 | Credentials (Etappe 1 ✅, Rest gebündelt) | — |
|
||||
> | TP31 | ⏳ | Reverse Proxy Caddy (1–4 ✅, 5–6 = Vor-Ort-Session) | — |
|
||||
> | TP32 | 🟢 | Nummern-Systematik (Konzept) | — |
|
||||
> | TP33 | 💡 | Sonos fern (Idee, zurückgestellt) | — |
|
||||
> | TP34 | 🔜 | Caddyfile via Nautobot/GC (Stub, Inventur-Handoff 2026-08-27) | — |
|
||||
> | TP35 | ⏳ | MCP-Schichtung + 3-Schicht-CLAUDE.md + Backup-Guard (Schicht 1+3+6 ✅) | — |
|
||||
> | TP36 | 🔜 | SSoT via Nautobot für teilprojekte.md-Live-Daten + Datei-Aufteilung | — |
|
||||
> | TP37 | 🔜 | Nautobot als Netzwerkdoku: Hosts/Container/Dienste + CF-Connectoren (Okay 08-30) | — |
|
||||
> | TP38 | 🔜 | OOB-Mgmt: untagged-VLAN99-Port je Switch | — |
|
||||
> | — | — | **34 archivierte TPs** in `teilprojekte-archiv.md` | — |
|
||||
> 📊 **Index/Statustabelle → [Gitea-Board](https://gitea.emsenhuber.net/admin/bf-infra/issues)** (siehe Kopf dieser Datei). Hier unten folgt nur noch die per-TP-Prosa.
|
||||
|
||||
### TP5.1 — DNS-Visibility & Flow-Observability für Low-Trust-Geräte (Airfryer-Fall) ▸ vorgemerkt
|
||||
- **Kontext (2026-07-08/09):** Airfryer „airschreier" (Philips/Versuni, ESP, `10.40.30.180`) bekam per DHCP-Option 6 `dns 1.1.1.1` als Override, weil das OTA-Update über den ap1-DoH-Gateway-Pfad nicht durchging (DoH-Latenz beim primitiven ESP-Stack — **kein** Content-Block, via Gateway-Logs bewiesen, s. `memory/ref_esp_ota_doh_not_block`). Nebenwirkung: public **1.1.1.1 = anonymer Consumer-Resolver ≠ accountgebundener Gateway-DoH** (`px35ynlol3.cloudflare-gateway.com`) → **DNS-Sicht auf das Gerät weg**, Gerät umgeht zudem die Filterung.
|
||||
@@ -456,11 +185,15 @@ nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Na
|
||||
- ⚠️ **Recht vor Scharfschalten prüfen (User privat, AT):** offenes WLAN + Portal berührt Impressumspflicht/Störerhaftung — **reine Namens-SSIDs ohne offenen Zugang sind unkritisch** (kein Fremd-Datenverkehr); im Zweifel nur die Beacon-Variante.
|
||||
- **Abh.:** ~~TP3-Rebuild ✅ (Standalone-APs — SSID-Änderung = 1 Deploy/GC-Job)~~ → **TP28 ✅** (CAPsMAN auf dem Core) + **TP22 ✅** (GC-Deploy-Pipeline). SSID-Änderung = **ein** Deploy auf den Core; Direkt-Edit am Gerät ist durch den Governance-Entscheid ausgeschlossen.
|
||||
|
||||
### TP14.4 — Session D: CF-Access-Profil für Claude ▸ 🔜 **AUSFÜHRBAR (Runbook 2026-08-19)** — `docs/tp14.4-cf-access-token-runbook.md` · nicht cutoff-kritisch
|
||||
> 📌 Ist-Stand geprüft: in `mcp/cloudflare/.env` stehen **weder** `CF_ACCESS_CLIENT_ID` **noch** `_SECRET` —
|
||||
> es ist also nichts halb erledigt. ⚠️ Das Secret existiert **nur im Moment der Rotation**.
|
||||
> Abnahme braucht **beide** Fälle (mit Headern antwortet / ohne Header 403), sonst ginge ein
|
||||
> bypass-Hostname wie `vw` fälschlich als Erfolg durch. Kein CF-Write erfolgt.
|
||||
### TP14.4 — Session D: CF-Access-Profil für Claude ▸ ✅ **IN TP41 T4 AUFGEGANGEN (2026-09-01)** — `docs/tp14.4-cf-access-token-runbook.md` (historisch)
|
||||
> ✅ **Erledigt über TP41 T4 (2026-09-01), nicht als eigenständiger `claude-mcp`-Token:** der
|
||||
> `claude-mcp`-Service-Token war die Basis (`t4a.py`), wurde **→ `zt-svc` umbenannt + rotiert** und über
|
||||
> Gruppe `zt-automation` konsolidiert. `mcp/cloudflare/.env` trägt jetzt **beide** Keys
|
||||
> `CF_ACCESS_CLIENT_ID`/`CF_ACCESS_CLIENT_SECRET` (Block „TP41 T4 zt-svc"), verifiziert
|
||||
> (`test_whoami.py` → `admin:true`, `common_name=zt-svc`). Handoff: [`handoff-20260901-tp41.md`](handoff-20260901-tp41.md) §T4.
|
||||
> 📌 *Überholt (Ist-Stand vor 09-01, bewusst erhalten):* „in `mcp/cloudflare/.env` stehen weder
|
||||
> `CF_ACCESS_CLIENT_ID` noch `_SECRET` — nichts halb erledigt." Das war bis zum 2026-09-01 richtig;
|
||||
> TP41 T4 hat die Keys dann geschrieben. Abnahme-Regel bleibt gültig (mit Headern antwortet / ohne 403).
|
||||
- CF-Token „claude code mcp" hat jetzt `Access: Service Tokens: Write`+`Read` → `claude-mcp` rotieren (`POST …/access/service_tokens/{id}/rotate`) → `CF_ACCESS_CLIENT_ID`/`_SECRET` in `mcp/cloudflare/.env` (chmod600). Memory `ref-cf-access-claude-profile`.
|
||||
- 📋 **Runbook: `docs/tp14.4-cf-access-token-runbook.md`** (2026-08-19). **Ist-Stand verifiziert:**
|
||||
`mcp/cloudflare/.env` enthält bisher weder `CF_ACCESS_CLIENT_ID` noch `_SECRET` — es ist nichts halb
|
||||
@@ -530,7 +263,28 @@ nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Na
|
||||
- **Reihenfolge:** (1) Client-IP-Weitergabe fixen (inkl. HA `trusted_proxies`) → (2) `/admin`-Pfade path-scoped schützen → (3) App-Limits + 2FA → (4) Edge-Rules → (5) CrowdSec/fail2ban mit CF-Bouncer.
|
||||
- **Abh.:** TP16 ✅ (Tunnel-HA). Verwandt: **TP20.1** (vw wandert auf Platform-Postgres — DB-HA ≠ Access, getrennt halten), **TP23** (dessen WARP-Managed-Network-Idee ist durch diesen Constraint **entlastet**: `vw` verlangt keine Device-Identity, also kollidiert „WARP zuhause aus" nicht mehr mit dem Access-Strang).
|
||||
|
||||
### TP16.3 — cloudflared-Reduktion: was der Mesh als Datenpfad kann (und was nicht) ▸ ⏳ **§1–§3 DURCH (2026-08-31): drei Connectoren live, `bf-public` healthy/12** — offen: Flip §5, Abbau §6 — `docs/tp16.3-nautobot-mesh-only-runbook.md §8`
|
||||
### TP16.3 — cloudflared-Reduktion: was der Mesh als Datenpfad kann (und was nicht) ▸ ✅ **ABGESCHLOSSEN 2026-09-01** — Flip (§5) + Abbau (§6) durch; öffentlich nur noch `bf-public` (+`fm`) — `docs/tp16.3-bf-public-ap-connector-runbook.md`
|
||||
|
||||
#### ✅ §6 Abbau — AUSGEFÜHRT 2026-09-01 (vom User vorgezogen, „es wird nichts mehr sein")
|
||||
|
||||
Die 7-Tage-Wartefrist war auf **User-Entscheid** hinfällig. Reihenfolge eingehalten: **erst Container,
|
||||
dann Tunnel** (umgekehrt gäbe es 530er).
|
||||
|
||||
- **Vorbedingung geprüft:** alle vier Namen auf `bf-public`, **kein** Name mehr an den Alttunneln ⇒
|
||||
Abbau gefahrlos.
|
||||
- **7 Container entfernt** (per exakter Namensliste, nicht per Filter — „Namen lesen, nicht Zeilen
|
||||
zählen"): LXC 400 `cloudflared-bfmm`/`-bfnas`, macmini `-bfpve`/`-bfnas`, NAS ep14 `-bfpve`/`-bfmm`,
|
||||
**plus `terpene-cloudflared`** — Letzterer auf zusätzlichen User-Entscheid, weil `420.teilzeitladen.xyz`
|
||||
jetzt über Caddy/CF läuft. **Kein Stack dahinter** ⇒ kein Wiederauferstehen.
|
||||
- **Beweis vor der Tunnel-Löschung:** `420.teilzeitladen.xyz` lieferte **mit bereits entferntem
|
||||
`terpene-cloudflared`** echten Origin-Inhalt (assetlinks-JSON, 200) — der Dienst hängt also nicht
|
||||
mehr am Tunnel.
|
||||
- **4 Tunnel gelöscht:** `bf-mm`, `bf-nas`, `bf-pve`, `terpene-db` — jede ID gegen die Behalten-Liste
|
||||
(`bf-public`, `fm`) geprüft.
|
||||
- **Schlusskontrolle:** nur noch `bf-public` (12) + `fm.emsenhuber.net` (4) healthy; alle vier
|
||||
BF-Namen und `420` weiterhin **200**.
|
||||
- ℹ️ Der `terpene-db`-Tunnel-Token stand kurz im `docker inspect`-Output — mit der Tunnel-Löschung
|
||||
**ungültig**, kein Rotationsbedarf.
|
||||
|
||||
#### 🔜 Follow-up F2 — `bf-public`-Connector auf die APs (Runbook 2026-08-30)
|
||||
**Runbook: [`tp16.3-bf-public-ap-connector-runbook.md`](tp16.3-bf-public-ap-connector-runbook.md)**
|
||||
@@ -636,7 +390,21 @@ nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Na
|
||||
- 🟡 **MikroMCPs `export_config` liefert einen unvollständigen Export** (301 B gegen 6,2 KiB bei
|
||||
direktem `/export`) — ein Rollback-Artefakt, das existiert und trotzdem leer ist. Für die Backups
|
||||
dieser Session wurden die MCP-Exporte verworfen und `/export file=…` verwendet.
|
||||
- 🔴 **Offen und entscheidungsbedürftig: Compliance steht auf 128/135, nicht 134/135.** §3.4 schreibt
|
||||
- ✅ **ERLEDIGT 2026-08-31: die sechs Drifts sind ins Soll gehoben, Compliance 139/140.**
|
||||
Entscheid Christoph: ins Template heben (nicht als Transaktion führen), und `/interface veth`
|
||||
bekommt eine **eigene ComplianceRule** — vorher war es das tragende Stück ohne jede Überwachung.
|
||||
Umgesetzt in `nautobot/mikrotik_routeros.j2` (Block `[7]`), `nautobot/ingest-ap-configcontext.py`
|
||||
(`ap.container`) und neu `nautobot/ingest-veth-rule.py`. **Kein Geräte-Write.**
|
||||
🔴 **Der veth-Export trägt zwei gerätevergebene MACs** (`mac-address`, `container-mac-address`,
|
||||
je AP verschieden). Ohne Vorbehandlung hätte die neue Regel auf **allen drei APs Dauer-Drift**
|
||||
erzeugt — also genau die immer-rote Zahl, die niemand mehr liest. Zwei `ConfigReplace`-Regeln
|
||||
normalisieren sie im Backup, eng auf die veth-Zeile verankert (`[^\n]*?` plus Lookbehind, damit
|
||||
VAP-/Bridge-/Ethernet-MACs nicht mitgefangen werden; Selbsttest im Skript).
|
||||
⚠️ **Ehrlich dazugesagt:** das kostet Backup-Treue — die veth-MACs stehen in `bf-golden-config`
|
||||
nicht mehr im Klartext. Vertretbar, weil RouterOS sie beim Neuanlegen ohnehin neu vergibt; was die
|
||||
Regel beweist, ist die **Existenz** des veth mit der richtigen Adressierung.
|
||||
*(Der ursprüngliche Befund, zur Nachvollziehbarkeit:)*
|
||||
- 🟢 **War: Compliance stand auf 128/135, nicht 134/135.** §3.4 schreibt
|
||||
Direkt-Writes für `veth` / `ip address` / `nat` vor, während `/ip address` und `/ip firewall` unter
|
||||
GC-Drift-Kontrolle stehen — **Runbook und Governance widersprechen sich.** Folge: je AP zwei neue
|
||||
`extra`-Drifts (`ip-address` mit `172.17.0.1/24 interface=veth-cf`, `ip-firewall-nat` mit dem
|
||||
@@ -1206,7 +974,26 @@ des Dimmers (= Lichtausfall in Diele UG/Wohnzimmer) wurde daraufhin **nicht** au
|
||||
- **Verwandt/Abgrenzung:** vw ist auch in **TP16** offen (CF-Access: `bypass`→WARP-geschützt) — **DB-HA ≠ Access**, getrennt behandeln. Reziprokes 2-Site-Muster analog **TP16**/**TP18**.
|
||||
- Abh.: **TP20** (Tier-1 Postgres muss stehen), **TP10** (WG-Transport für Phase-2), **TP18** (Backup-Schirm). Kein Blocker für TP21.
|
||||
|
||||
### TP23 — DNS-Policy & Self-Service-Ausnahmen ▸ ⏳ **STUFE 1 DURCH, STUFE 2 VORBEREITET (2026-08-18)**
|
||||
### TP23 — DNS-Policy & Self-Service-Ausnahmen ▸ ⏳ **STUFE 1–5 DURCH (2026-09-04); offen nur Stufe 6 (Bypass-Sperre, in TP5)**
|
||||
> 🟢 **Update 2026-09-04 — Stufe 4 + 5 gebaut, live verifiziert. Der `.16`-Text unten ist überholt**
|
||||
> (Stufe 2 lebt seit 08-26 auf dem Paar `agh-bf1`/`agh-bf2` = `.36`/`.37`, LXC 110/111 — s. Ist-Stand-Block):
|
||||
> - **Stufe 4 (CIDR-Substrat):** 7 VLAN-Gruppen + `dns-bypass-exempt` in `clients.persistent` auf beiden
|
||||
> Instanzen; Policy-Matrix (INFRA/MEDIA/MGMT `filtering=aus`, GUEST safe-search+parental an). Neuer
|
||||
> AGH-API-User `automation` (PW in `~/.secrets` → TP30). Sync-Werkzeug `adguard/agh-sync.py`
|
||||
> (`check`/`push`), Repo-SSoT `adguard/AdGuardHome.yaml` mit **redigierten** Hashes. Invariante `.36==.37`.
|
||||
> - **Stufe 5 (HA-Self-Service):** `agh-exception.py` (RMW-CLI, `allow-domain`/`unallow`/`unfilter`/`refilter`)
|
||||
> auf HAOS deployt; `shell_command` + 5 Helper + Timer + 2 Automations (`ha-mcp`). Button → Domain für
|
||||
> 15 min/1 h/4 h entsperren, nativer `timer` revertiert; RouterOS-`jit-dns-bypass`-Backstop erst mit Stufe 6.
|
||||
> Doku: `adguard/README.md` + `adguard/ha-self-service.md`. End-to-End getestet (Start + Ablauf).
|
||||
> - **Offen:** nur **Stufe 6** (DNS-Bypass-Sperre) — bewusst NICHT geschaltet. Runbook für eine
|
||||
> **separate Session**: [`docs/tp23-stufe6-bypass-sperre-runbook.md`](tp23-stufe6-bypass-sperre-runbook.md).
|
||||
> 🔴🔴 **HARTES VOR-ORT-GATE:** macht AGH `.36/.37` zum harten DNS-SPOF, aus der Ferne nicht
|
||||
> reparierbar → **NUR vor Ort, NICHT während Christoph abwesend ist** (2026-09-06: ~1 Woche weg →
|
||||
> in dem Fenster gar nicht anfangen). Methodik: log-only-Vorstufe zuerst, Drop mit Auto-Revert zuletzt.
|
||||
> - **WARP-Managed-Network (Stufe 2 im alten Plan)** bleibt offen (TP41-nah). Der `.16`-basierte
|
||||
> Abschnitt darunter ist die historische Fassung (2026-08-18), bewusst erhalten.
|
||||
|
||||
**[Historische Fassung 2026-08-18 — `.16`-basiert, durch den Block oben überholt:]**
|
||||
- ✅ **Stufe 1 — DoH auf dem Core scharf** (`routeros/tp23-stufe1-doh-core.rsc`), schliesst zugleich
|
||||
**TP21.1 TODO 1**. `use-doh-server=https://px35ynlol3.cloudflare-gateway.com/dns-query`,
|
||||
**`verify-doh-cert=yes`**. `servers=1.1.1.1` bleibt als Bootstrap fuer den DoH-Hostnamen stehen.
|
||||
@@ -1291,7 +1078,7 @@ des Dimmers (= Lichtausfall in Diele UG/Wohnzimmer) wurde daraufhin **nicht** au
|
||||
- **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 ▸ 🔬 **FUND E OFFEN, HEBEL 1 LÄUFT (2026-08-31 08:09): `ft-over-ds=no` auf `sec-main`, Messung bis 2026-09-01** · Kern erledigt: 🟢 **(2026-08-22) Dead Spot Terrasse repariert** (43 % → 9 % Verlust, 20,4 s → 1,0 s). **Fund F ✅ aufgelöst (08-24, geräteseitig — kein Netzfehler)**, **5-GHz-Umfeldscan ✅ (08-24)**, Kanalplan für AP 3 ✅ gerechnet. Offen nur noch die Umsetzung, wenn der dritte AP kommt. Nicht mehr kritischer Pfad — Sammel-TP für Christophs Beobachtungen 1–6
|
||||
### TP25 — WLAN-Stabilisierung ▸ ⏳ **FUND E ✅ GESCHLOSSEN 2026-09-02: die Abschlussmessung ist ruhig (4 reauth in 8,6 h, 0 Ausfälle, Verlauf 218→40→4) ⇒ `7.24.1` (TP27) war die Ursache, nicht `ft-over-ds`. Hebel 1 widerlegt+zurückgebaut, Hebel 2–4 entfallen, kein Geräte-Write** ([Handoff](handoff-20260902-tp25-fund-e-messung.md)) — **offen bleibt nur: ap2 unterperformt (2 m/−80 dBm, 23:02-Befund) als eigener In-situ-Unterpunkt** · Kern erledigt: 🟢 **(2026-08-22) Dead Spot Terrasse repariert** (43 % → 9 % Verlust, 20,4 s → 1,0 s). **Fund F ✅ aufgelöst (08-24, geräteseitig — kein Netzfehler)**, **5-GHz-Umfeldscan ✅ (08-24)**, Kanalplan für AP 3 ✅ gerechnet. Offen nur noch die Umsetzung, wenn der dritte AP kommt. Nicht mehr kritischer Pfad — Sammel-TP für Christophs Beobachtungen 1–6
|
||||
> 📚 **Kondensiert am 2026-08-23 (Doku-Session, Punkt F).** Dieser Abschnitt war mit 394 Zeilen
|
||||
> 18 % der Datei. Die **Langfassung steht vollständig und unverändert** im Archiv:
|
||||
> [`teilprojekte-archiv.md` → TP25 (Langfassung)](teilprojekte-archiv.md#tp25-lang) — Messchronik (A)–(G),
|
||||
@@ -1542,10 +1329,18 @@ die alte Liste führte `2g-probe-delay` an, das aber **Band-Steering** adressier
|
||||
|
||||
| # | Hebel | Begründung der Reihenfolge | Risiko | Stand |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **`ft-over-ds=no`** auf `sec-main` | nimmt die Änderung vom 08-17 zurück; FT bleibt über `ft=yes` (over-the-air) erhalten. Kleinster Eingriff, der die verdächtige Achse trifft | gering | 🔬 **gezogen 2026-08-31 08:09**, Messung läuft |
|
||||
| 2 | `ft=no` auf `sec-main` | falls (1) nicht reicht: FT komplett aus. Kostet Roaming-*Geschwindigkeit*, nicht Roaming | mittel | 🔜 nur wenn (1) nicht greift |
|
||||
| 3 | `2g-probe-delay=yes` (2,4-GHz-Configs) | MikroTiks *dafür gebautes* Werkzeug; verzögert nur Probe-Antworten und **kann keinen Client stranden lassen**. Adressiert die **Band-Oszillation** — ein anderes Symptom | sehr gering | 🔜 |
|
||||
| 4 | `signal-range`-Boden per `access-list` (Fund E im Original) | **kann Clients aussperren** — genau das war 08-22 das Gegenargument; nur mit gemessenem Wert | hoch | 🔜 |
|
||||
| 1 | **`ft-over-ds=no`** auf `sec-main` | nimmt die Änderung vom 08-17 zurück; FT bleibt über `ft=yes` (over-the-air) erhalten. Kleinster Eingriff, der die verdächtige Achse trifft | gering | ❌ **widerlegt** — lief 6,4 h allein → 124× (≈19/h) + 2 Ausfälle, **zurückgebaut 2026-09-01** |
|
||||
| 2 | `ft=no` auf `sec-main` | falls (1) nicht reicht: FT komplett aus. Kostet Roaming-*Geschwindigkeit*, nicht Roaming | mittel | ✅ **gezogen 2026-09-04** (User-Entscheid, Dauerzustand — Template + bf-golden-config + Nautobot-Sync) |
|
||||
| 3 | `2g-probe-delay=yes` (2,4-GHz-Configs) | MikroTiks *dafür gebautes* Werkzeug; verzögert nur Probe-Antworten und **kann keinen Client stranden lassen**. Adressiert die **Band-Oszillation** — ein anderes Symptom | sehr gering | ⏹️ entfällt (Fund E geschlossen) |
|
||||
| 4 | `signal-range`-Boden per `access-list` (Fund E im Original) | **kann Clients aussperren** — genau das war 08-22 das Gegenargument; nur mit gemessenem Wert | hoch | ⏹️ entfällt (Fund E geschlossen) |
|
||||
|
||||
> ✅ **Ergebnis 2026-09-02 (Abschlussmessung, [Handoff](handoff-20260902-tp25-fund-e-messung.md)):** Der Sturm ist mit
|
||||
> `ft-over-ds=yes` **und** 7.24.1 verschwunden — 09-02 nur **4 reauth in 8,6 h** (alle iPhone `F2:62`, isolierte
|
||||
> Einzel, 0 Ausfälle), Verlauf **218 → 40 → 4**. Vorbedingung geprüft (Core-Uptime 1d18h, `caps joined=0`).
|
||||
> ⇒ **7.24.1 war die Ursache/der Fix, nicht `ft-over-ds`.** Hebel 1 widerlegt+zurückgebaut, Hebel 2–4 entfallen,
|
||||
> **kein Geräte-Write** (Soll stand: `ft=yes ft-over-ds=yes`, Compliance 140/140). **Am 2026-09-04 hat
|
||||
> Christoph `ft=no` auf `sec-main` als Dauerzustand entschieden** (Hebel 2 doch gezogen). Der folgende Detailblock zu
|
||||
> Hebel 1 ist historisch.
|
||||
|
||||
#### 🔬 Hebel 1 — gezogen am 2026-08-31 08:09, Messung läuft bis 2026-09-01
|
||||
|
||||
@@ -1628,16 +1423,20 @@ während eines Calls deployen, `/system backup` je AP vorher.
|
||||
- 🔴 **Ein vom Pin abgewiesener Verbindungsversuch ist in Ping-Daten nicht von einem Funkloch zu
|
||||
unterscheiden** — und der Manager protokolliert ihn auf `info`-Ebene **gar nicht**. Android quittiert
|
||||
die Abweisung mit „Verbindung fehlgeschlagen" und **wählt das Netz ab**; danach misst der Rest des
|
||||
Rundgangs Stille. Die Klick-Konsole schlägt deshalb Alarm, sobald das gepinnte Gerät nirgends hängt,
|
||||
und schreibt nach 45 s `UNERREICHBAR=apX` — denn „der Gegen-AP trägt hier nicht" **ist das Messergebnis**.
|
||||
- 📐 **Eine Runde, zwei Messpunkte** (Christophs Aufbau 2026-08-22): das frei roamende iPhone zeigt, was
|
||||
ein normaler Client wählt — interessant ist der **andere**. Das S22 wird per `access-list` auf den
|
||||
Gegen-AP gezwungen ([`tp25-pin-s22.sh`](tp25-pin-s22.sh)). Gute Referenz + schlechte Sonde = die
|
||||
Abdeckung steht, die Rückfallebene nicht. Memory `ref_gegen_ap_messung`.
|
||||
Rundgangs Stille. Die Klick-Konsole schlägt deshalb Alarm, sobald ein **gepinnter** Client nirgends
|
||||
hängt (`sta_iface=absent` in `sampler-<name>.csv`) — denn „der Gegen-AP trägt hier nicht" **ist das
|
||||
Messergebnis**.
|
||||
- 📐 **Eine Runde, N Messpunkte** (seit 2026-09-04): die frei roamenden Clients zeigen, was ein normaler
|
||||
Client wählt — interessant sind die **gepinnten**. Jeder Client wird **band-genau** auf einen AP
|
||||
gezwungen ([`tp25-pin-multi.sh`](tp25-pin-multi.sh), `TP25_PINSPEC="name|mac|ap|band;…"`), direkt aus
|
||||
der Klick-Konsole. Gute Referenz + schlechte Sonde = die Abdeckung steht, die Rückfallebene nicht.
|
||||
Memory `ref_gegen_ap_messung`. *(Die alte 2-Client-`access-list`-Automatik über `tp25-pin-s22.sh` ist
|
||||
mit dem Multi-Pin-Umbau entfallen; `tp25-pin-s22.sh` liefert nur noch die `map`.)*
|
||||
- ▶️ **Start ohne Werkzeugkette: `bash docs/tp25-runde.sh [name]`** — legt den Lauf unter
|
||||
`docs/messdaten/tp25-runde-<name>/` an, friert die AP-Karte ein, startet Konsole (Port 3031) und
|
||||
Messung, sagt die **vom Interface gelesene** Adresse fürs Telefon an und löst beim Beenden den Pin.
|
||||
Auswertung: `tp25-gehweg-auswertung.py --dir …`.
|
||||
Messung, sagt die **vom Interface gelesene** Adresse fürs Telefon an. In der Konsole: **pinnen**
|
||||
(N Clients je AP/Band) → **gehen** (🚶/📍) → **Räume antippen** → **stoppen**; beim Beenden löst der
|
||||
Wrapper den Multi-Pin. Auswertung: `tp25-gehweg-auswertung.py --dir …`.
|
||||
- ℹ️ **Und das alles passiert TROTZ aktivem 802.11k/v und FT** (`st-main` mit `rrm=yes`/`wnm=yes`,
|
||||
`ft-over-ds=yes`, live geprüft). Die Merkregel `ref_ft_is_not_roaming` („11k/v fehlen") ist
|
||||
**historisch**. Bei −48…−55 dBm kostet eine Übergabe 0–2,6 s, meist unter einer halben Sekunde —
|
||||
@@ -1663,6 +1462,53 @@ die Redundanzfrage oben.
|
||||
- **Abh.:** TP22 ✅ (GC-Deploy-Pipeline). Verwandt **TP3.2** (`docs/wifi-p750w-coverage-and-map.md`),
|
||||
**TP29** (nutzt dieselbe Datenquelle als Sensor). **Kein Blocker für irgendetwas.**
|
||||
|
||||
#### 🔬 Fund E — 2026-09-01: der `ap2`-Teilbefund (gültig) und eine widerlegte Heilungs-Wertung
|
||||
|
||||
**Anlass:** Christoph meldete **2026-08-31 23:02** eine Störung am Schreibtisch (5G, iPhone, kein
|
||||
Telefonat). Analyse (alles read-only am Manager `crs326-core`):
|
||||
|
||||
- **AP-Karte** (stabil seit letztem CAP-Rejoin 15:57, kein Rejoin danach — Attribution belastbar):
|
||||
`cap-wifi5/6 = ap2`, `cap-wifi3/4 = ap3`, `cap-wifi1/2 = ap1` (funkstill, Radios da, 0 Clients).
|
||||
- **23:02-Ereignis:** iPhone `F2:62:4C:E1:AF:09` ping-pongt im Sekundentakt `cap-wifi5 ↔ cap-wifi6`
|
||||
= **ap2s 5G (5220) ↔ ap2s 2,4G (ch11/2462)** — Band-Steering-Thrash auf **demselben** AP, plus
|
||||
`disconnected, not responding` um 22:37:40 (−76) und **23:01:00** (−82). Feldstärke der Roams
|
||||
**−75…−88 dBm**.
|
||||
- 🔴 **Christophs Fakt kippt die Coverage-Deutung:** iPhone und **ap2 nur 2 m** entfernt, gleicher
|
||||
Raum, ap2 auf 2,3 m. Bei 2 m Sicht wären −35…−45 dBm normal. −80 auf 2 m ist **kein** Coverage-
|
||||
und **kein** FT-Problem. Dazu: **aktuell 0 Clients auf ap2**, alle 29 auf ap3 — die Clients *meiden*
|
||||
ap2. ⇒ **ap2s Funk selbst unterperformt** (RF/Antenne/HW) und/oder die **DTU-Störung auf ap2/ch11**
|
||||
(Transaktion `TP17.1-dtu-pin-ap2`, Wechselrichter `54:F2:9F:12:51:F0` mit −59 dBm auf ap2s 2,4-Radio).
|
||||
- **In-situ zu messen** (nachts nicht möglich — Phone idle auf ap3): Registration-Signal live prüfen,
|
||||
während ein Client auf ap2 hängt; Kandidaten-Eingriffe — DTU-Pin lösen/verlegen, `dirtyvader-main`
|
||||
auf ap2 temporär deaktivieren (ap3 übernimmt den Schreibtisch), ap2-Antenne/HW prüfen. **Keine
|
||||
Änderung ohne diese Messung.**
|
||||
|
||||
🔴 **WIDERRUFEN am 2026-09-01 vormittags — der zweite Teil dieses Abschnitts war ein Messfehler.**
|
||||
Ursprünglich stand hier: „Fund E ist im sauberen Fenster geheilt — 0× `reauthenticating` seit dem
|
||||
14:36-Reboot (`sinceMinutes=1440`, total 0), also hat Hebel 1 sein Ziel erreicht."
|
||||
|
||||
**Warum das nicht trägt:** `get_log` liest den **flüchtigen Ringpuffer des Routers**, nicht den
|
||||
Kollektor. Live nachgemessen fasst er **1000 Zeilen und reicht bis 01.09. 00:38:58 zurück** — keine
|
||||
9 Stunden. Der Core-Reboot um 14:36 hatte ihn geleert; der 31.08. Vormittag war darin gar nicht
|
||||
enthalten. `total 0` hieß **„im Puffer nichts", nicht „in 24 h nichts"**. Das ist exakt die Falle,
|
||||
wegen der am 30.08. das persistente Logging gebaut wurde.
|
||||
|
||||
**Was der Kollektor zeigt:** im upgrade-freien Fenster 08:09–14:36 (Hebel 1 **allein**) **124×
|
||||
`reauthenticating`** — 09h=1 · 11h=2 · 12h=20 · 13h=31 · 14h=70, **alle vom iPhone allein**, dazu
|
||||
Christophs zwei erlebte Ausfälle 13:16 und 14:23. Zwischen 09:00 und 14:36 lag **kein Reboot**.
|
||||
⇒ Hebel 1 wurde am 2026-09-01 **zurückgebaut**; der Rückbau ist das entscheidende Experiment
|
||||
(s. Ist-Stand-Block oben).
|
||||
|
||||
✅ **Der `ap2`-Teilbefund oben bleibt davon unberührt und gültig** — er ist unabhängig gemessen und
|
||||
erklärt die 23:02-Störung, die weder FT noch Coverage erklärt.
|
||||
|
||||
**Commit-Weg (wartet auf Christophs Go — git-push-Kette):** Template `nautobot/mikrotik_routeros.j2`
|
||||
**Z. 220** `sec-main` von `ft-over-ds=yes` → `ft-over-ds=no`; dann Template-Repo nach Nautobot syncen,
|
||||
`gc-configplan.py --refresh-compliance` (Backup→Intended→Compliance), dann
|
||||
`gc-transaktion.py commit --change-id TP25-fund-e-ft-over-ds`. Danach `wifi-security` wieder driftfrei.
|
||||
🔴 Kreuzt git-push (Backup-Guard + Commit-Hinweis-Regel) und Live-Nautobot-Jobs — **nicht autonom.**
|
||||
Handoff: [`handoff-20260901-tp25-ap2-verdacht.md`](handoff-20260901-tp25-ap2-verdacht.md).
|
||||
|
||||
<a id="tp28"></a>
|
||||
|
||||
### TP28 — WLAN über CAPsMAN auf `crs326-core` ▸ ✅ **ap3 LIVE (2026-08-30)** — wieder geöffnet und durchgezogen
|
||||
@@ -1933,6 +1779,10 @@ Umzug **nebeneinander**, ein zweiter AP am selben Punkt bringt nichts und stört
|
||||
| 2 | **IoT-WLAN-PSK** (`sec-iot`) | `dirtyvader-iot`, 26 Clients | steht **im Klartext** im TP17-Text ⇒ auch in der **Git-Historie**; Redigieren holt ihn dort nicht raus | Hebel `multi-passphrase` am Core verifiziert vorhanden, Tabelle leer | 23 Shellys per Skript + **3 von Hand** (`.249` NSPanel Pro, `.244` Nuki Bridge, `.227` SwitchBot) |
|
||||
| 3 | **Shelly-Gerätepasswort** *(vormals TP17.2)* | 23 Shellys | Härtung (bisher **keine** Auth auf den Geräten) | ✅ Werkzeug fertig (`migrate.py cmd_auth` + Digest-Fallback) | **je Gerät ein HA-Re-Auth-Flow** — das ist der Aufwand, nicht `SetAuth` |
|
||||
| 4 | **CF-Access-Service-Token** (`CF_API_TOKEN`) | Cloudflare-Zugang, s. TP14.4 | ⏳ **läuft am 2027-01-09 ohnehin ab** — harter Termin, unabhängig vom Projektende | Runbook liegt (`tp14.4-cf-access-token-runbook.md`) | Token neu ausstellen + `~/.secrets` nachziehen; **account-owned**, anderer verify-Endpoint |
|
||||
| 5 | **Nautobot-Tokens** (`NAUTOBOT_SUPERUSER_API_TOKEN`, `NAUTOBOT_GITEA_TOKEN`) | Nautobot-Superuser + Gitea-Anbindung | 🔴 in der TP16.3-§2/§3-Session (2026-08-31) durch schwache `sed`-Maskierung **ins Transkript** geraten | Werte in `docs/nas-vlan20/stacks/210-nautobot.yml` (gitignored) | neu ausstellen + Stack-YML nachziehen; Superuser-Token wird von den `gc-*`-Skripten gelesen |
|
||||
| 6 | **MariaDB `root`** (LXC 302, `10.40.20.23`) | root-DB-Login | 🔴 am 2026-09-01 (TP39) ins Transkript geraten — die `/root/.my.cnf` trug `password <wert>` **ohne `=`**, die Feld-Maskierung ankerte auf `=` und griff nicht | Wert in `/root/.my.cnf` (chmod 600) | `SET PASSWORD` + `.my.cnf` nachziehen; **kein** externer Konsument (Dienste nutzen eigene DB-User) ⇒ billigste Rotation der Liste |
|
||||
| 7 | **`TERPENE_ANDROID_KEYSTORE_PW`** | Terpene-Android-TWA-Signing (`android/android.keystore`, alias `terpene`) | 🔴 am 2026-09-01 (TP41) durch **Regex-Suffix-Loch** (`_PW` nicht abgedeckt) ins Transkript geraten | Wert in `~/.secrets/credentials.env` + Keystore-Datei | **Store-/Key-Passwort** via `keytool -storepasswd`/`-keypasswd` ändern + `credentials.env` nachziehen; Konsument = Android-Build/Play-Signing (**Cross-Projekt blaueblüten**) — den **Key selbst NICHT** neu erzeugen |
|
||||
| 8 | **`N8N_SMTP_PASS`** (Gmail-App-PW für `johnny.claw.0x00@gmail.com`) | SMTP-Versand aus n8n (Portainer-Stack 174 `n8n`, macmini) | 🔴 am 2026-09-01 (n8n-mcp-SSRF-Session) beim Ausgeben des Stack-174-Files ins Transkript geraten — Redaktionsmuster hatte `PASSWORD`, aber **nicht bare `PASS`** → `N8N_SMTP_PASS=<wert>` blieb stehen | Wert in Portainer-Stack 174 (`environment`) | **Gmail-App-Passwort widerrufen** (Google-Konto → App-Passwörter) + neues erzeugen, Stack-174-Env nachziehen + redeploy; Konsument = n8n-SMTP-Node(s) |
|
||||
|
||||
> ✅ **Der Leak-MECHANISMUS hinter #1 ist seit 2026-08-31 zu — der Wert bleibt trotzdem verbrannt.**
|
||||
> Alle sechs Skripte im Repo, die `sshpass -p <PW>` benutzten (`nautobot/gc-transaktion.py` und
|
||||
@@ -1944,6 +1794,28 @@ Umzug **nebeneinander**, ein zweiter AP am selben Punkt bringt nichts und stört
|
||||
> also nicht blind. 🔴 **Das ändert an #1 nichts:** ein Wert, der einmal in einem Transkript stand,
|
||||
> wird nicht dadurch sauber, dass der Weg dorthin geschlossen ist. Rotation bleibt fällig.
|
||||
>
|
||||
> 🔴 **Posten #6 ist die dritte Maskierungs-Panne derselben Klasse** (nach `SHELLY_DEVICE_PW` 08-28
|
||||
> und den Nautobot-Tokens 08-31): das Muster ankerte auf ein **Trennzeichen** (`=`), das im
|
||||
> konkreten File gar nicht stand (`password <wert>` mit Leerzeichen). **Merkregel, jetzt zum dritten
|
||||
> Mal:** vor jedem Ausgeben einer Secret-Datei den **Schlüsselnamen** ankern und das ganze Feld
|
||||
> ersetzen, nie auf ein Trennzeichen vertrauen, das evtl. fehlt — und Werte gar nicht erst suchen,
|
||||
> um sie zu sehen. #6 ist zugleich der **billigste** Posten (kein externer Konsument), aber die
|
||||
> Panne dahinter ist der teure Teil.
|
||||
>
|
||||
> 🔴 **#7 ist die vierte Maskierungs-Panne derselben Klasse** (nach `SHELLY_DEVICE_PW` 08-28,
|
||||
> Nautobot-Tokens 08-31, MariaDB-root 09-01): diesmal ein **Regex-Suffix-Loch** — das Muster
|
||||
> `(TOKEN|PASS|PASSWORD|SECRET|KEY|CLIENT_ID)` deckte den Suffix `_PW` **nicht** ab, also blieb der
|
||||
> Wert von `TERPENE_ANDROID_KEYSTORE_PW` beim maskierten Lesen stehen. **Dieselbe Merkregel, erweitert:**
|
||||
> die Alternation muss `PW`/`PWD` mit enthalten (`…|PW|PWD|…`), sonst greift die Feld-Ersetzung nicht.
|
||||
>
|
||||
> 🔴 **#8 ist die fünfte Maskierungs-Panne derselben Klasse** (SHELLY 08-28, Nautobot-Tokens 08-31,
|
||||
> MariaDB-root #6, Keystore-`_PW` #7): diesmal enthielt das Muster zwar `PASSWORD`, aber **nicht das
|
||||
> bare `PASS`** — `N8N_SMTP_PASS` endet auf `PASS`, nicht `PASSWORD`, also blieb der Wert stehen.
|
||||
> **Die Merkregel steht jetzt zum fünften Mal da und wurde zum fünften Mal gebrochen** — Konsequenz
|
||||
> ist nicht noch eine Notiz, sondern ein **fixes, geteiltes Redaktions-Snippet**, das man nicht jedes
|
||||
> Mal neu (und falsch) tippt: `sed -E 's/([A-Z0-9_]*(PASS|PASSWORD|PWD|PW|TOKEN|SECRET|KEY|BEARER))=[^[:space:]]*/\1=<redacted>/g'`
|
||||
> — ankert auf den **Schlüsselnamen inkl. Präfix** und deckt alle bisher gesehenen Suffixe ab.
|
||||
>
|
||||
> ℹ️ **#3 war bis 2026-08-24 TP17.2** und ist jetzt vollständig hier (s. Detailabschnitt unten) —
|
||||
> es benutzt denselben Geräte-Durchgang wie #2, **ein Reboot statt zwei**. #4 gehört sachlich zu
|
||||
> **TP14.4**, das als TP bestehen bleibt (dort steckt das CF-Access-Profil, nicht nur der Token).
|
||||
@@ -2136,7 +2008,16 @@ unabhängig vom gebündelten Durchgang.**
|
||||
|
||||
|
||||
<a id="tp31"></a>
|
||||
### TP31 — Reverse Proxy für innen und außen; cloudflared von sechs Knoten auf einen ▸ 🔜 **GEPLANT 2026-08-25**
|
||||
### TP31 — Reverse Proxy für innen und außen; cloudflared von sechs Knoten auf einen ▸ ✅ **ABGESCHLOSSEN 2026-09-01**
|
||||
> ✅ **Durch — Schritt 5+6 sind über den Piloten [TP16.3](#tp163) miterledigt (2026-09-01):** `bf-public`
|
||||
> **healthy, 12 Connectoren** auf ap1/ap2/ap3; `vw`/`hass`/`n8n`/`gitea` laufen über CF → **Caddy**
|
||||
> (`https://10.40.20.40:443`), die drei Alttunnel `bf-nas`/`bf-pve`/`bf-mm` **gelöscht**. Damit steht das
|
||||
> Zielbild: **eine** Host→Origin-SoT im `Caddyfile`, öffentlich nur vier Namen. Abnahme-Tool
|
||||
> [`caddy/cf-sync.py`](../caddy/cf-sync.py) **grün** (2026-09-02: die vier geflippten Namen wurden vorher
|
||||
> als Fehlalarm gemeldet — das Tool prüfte nur `http://`, gebaut ist `https://…:443`; Einzeiler-Fix in `cf-sync.py`).
|
||||
> 📎 **Überholt:** Schritt-6-Teil „MCP-Clients auf FQDN umstellen" ist durch **TP35 Schicht 1**
|
||||
> **andersherum** entschieden (FQDN→LAN-IP). 🧹 Rest-Kleinkram (verwaistes `grafana`-Zertifikat) läuft
|
||||
> mit dem Grafana-Wiederaufbau nach TP32.
|
||||
> **Auslöser (User 2026-08-24):** „ich weigere mich, für public applications 2 cloudflare container zu
|
||||
> installieren. … ich habe [den Core] unter der prämisse gekauft, dass über diesen dann auch die public
|
||||
> apps laufen können. wir wollten doch den core als single point of failure platzieren."
|
||||
@@ -2241,10 +2122,14 @@ Alles andere ist intern; **19 Ingress-Zeilen über drei Tunnel werden EINE Catch
|
||||
🔑 **Deshalb als Paar bauen** — TP32 reserviert `110`/`111` fuer DNS, und die geloeschten
|
||||
Altlasten hiessen nicht zufaellig `adguard-bf1`/`adguard-bf2`: die Redundanz war urspruenglich
|
||||
schon einmal geplant. **Ein einzelner AGH waere ein DNS-SPOF auf pve.**
|
||||
5. **Tunnel `bf-public`** + Connectoren auf ap1/ap2, CNAMEs umhängen (`n8n` → `gitea` → `hass` → `vw`).
|
||||
6. **Abbau:** `bf-nas`/`bf-pve`/`bf-mm` löschen, sechs Container weg, SSH-Browser-Rendering entfällt,
|
||||
**MCP-Clients auf FQDN umstellen** (`~/.claude.json` spricht heute `10.40.20.105:9583` und
|
||||
`10.40.20.173:3000` roh; `n8n-mcp`/`gitea-mcp` kommen dabei wieder in Betrieb).
|
||||
5. ✅ **ERLEDIGT via [TP16.3](#tp163) §5 (2026-09-01) — Tunnel `bf-public`** + Connectoren auf ap1/ap2/ap3
|
||||
(12 conns healthy), CNAMEs geflippt (`n8n`/`gitea`/`hass`/`vw` → CF → Caddy `https://10.40.20.40:443`).
|
||||
Je Name einzeln geflippt, dazwischen gemessen; Antwortzeiten vorher/nachher unverändert.
|
||||
6. ✅ **ERLEDIGT via [TP16.3](#tp163) §6 (2026-09-01) — Abbau:** `bf-nas`/`bf-pve`/`bf-mm` gelöscht,
|
||||
7 cloudflared-Container weg. 🔴 **Ausnahme, bewusst umgekehrt:** der Teil „**MCP-Clients auf FQDN
|
||||
umstellen**" ist durch **TP35 Schicht 1** **andersherum** entschieden — `gitea-mcp`/`n8n-mcp` sprechen
|
||||
heute die **LAN-IP** (`10.40.20.167:3000`/`:3001`), nicht den FQDN. Der ursprüngliche Plan ist damit
|
||||
gegenstandslos, nicht offen.
|
||||
|
||||
#### ✅ Stand 2026-08-25 nach dem Bau — Caddy laeuft, zwei Backends fielen dabei auf
|
||||
**17 von 17 Zertifikaten** per DNS-01 von Let's Encrypt geholt, Dienst `active`+`enabled`,
|
||||
@@ -2469,16 +2354,6 @@ kann in Ruhe nachziehen.
|
||||
|
||||
---
|
||||
|
||||
### TP34 — Caddyfile via Nautobot/GC (generische Reverse-Proxy-Schnittstelle) ▸ 🔜 STUB
|
||||
> **Konzept + Architektur-Skizze:** [`docs/handoff-20260827-inventur-und-architektur.md`](handoff-20260827-inventur-und-architektur.md) — bitte dort weiterlesen (Architektur-Abschnitt).
|
||||
- **Scope:** Reverse-Proxy-Hosts werden im **Nautobot-Datenmodell** gepflegt (Site, Host, Backend-Spec). **Golden Config** rendert den Caddyfile aus den Daten, Diff-Check gegen die Live-Version auf `caddy-bf1`, Compliance-Checks + Transaktionen identisch zum bestehenden Workflow für Router-Configs.
|
||||
- **Auslöser (Inventur 2026-08-27):** der Caddyfile (`bf-infra/caddy/Caddyfile`) ist heute **manuell gepflegt** — kein Drift-Check, keine Transaktionen, andere Projekte können keine Sites anlegen ohne Christoph. Lösung: **Nautobot/GC**, kein Caddy-API-Sidecar (kein zweites SSoT).
|
||||
- **Erster Anwendungsfall:** `terpene.teilzeitladen.xyz → http://10.40.20.167:8890` (Mac-mini-Backend, dort PostgREST + sync + web via lokalem Caddy `:8890`). Vor TP34: manueller Quick-Win-Caddy-Block.
|
||||
- **Abh.:** TP22 (GC-Pipeline) ✅ vorhanden · TP23 (DNS-Policy + Caddy-Voraussetzungen) ✅ Stufe 1. Hängt an **nichts**, eigene Implementierung im Runbook nach dem Quick-Win.
|
||||
- **Status:** 🔜 Stub; Konzept + Architektur-Skizze vollständig in Handoff-Datei. Implementierung in eigenem Runbook nach terpene-Caddy-Quick-Win.
|
||||
|
||||
---
|
||||
|
||||
### TP35 — MCP-Schichtung global/projekt/user + 3-Schicht-CLAUDE.md + Announcement-Mechanismus + Backup-Guard ▸ ⏳ **ANGELEGT 2026-08-28, Schicht 1 (FQDN→IP) + Schicht 3 (globale Regeln) + Schicht 6 (Skill) ✅**
|
||||
- **Auslöser:** Bestandsaufnahme Session 2026-08-28 (Handoff `docs/handoff-20260828-pre-opencode-migration.md`). Erkenntnis: MCP-Configs sind heute über `~/.config/opencode/opencode.jsonc` UND `~/.claude.json` verstreut, ohne klares Schema.
|
||||
- **Befund (geprüft):** 11/12 Backups im Verzeichnis `~/dev/.pre-opencode-migration-backups/20260828-150335/` gzip-valid; `uwe-job-bewerbung.tar.gz` korrupt (Source unverändert da). Repos und globale Configs md5-/HEAD-identisch zum Vor-Session-Stand. Synology-Drive-Sync aktiv (Anwender, manuell).
|
||||
@@ -2496,17 +2371,17 @@ kann in Ruhe nachziehen.
|
||||
|
||||
---
|
||||
|
||||
### TP36 — SSoT via Nautobot für `teilprojekte.md`-Live-Daten + Datei-Aufteilung ▸ 🔜 ANGELEGT 2026-08-28, Scope-Ausarbeitung eigene Session
|
||||
- **Auslöser:** Skill-Run 2026-08-28 (`docs/handoff-20260828-session-a-projektstatus.md`) lieferte „Nächster Schritt (2026-08-26): TP31 Schritt 5" als Output, obwohl seit dem 26. drei Folge-Sessions parallel offen waren. **Manuell gepflegte Doku mit Live-Daten verliert gegen die Realität, sobald sie lang wird.**
|
||||
- **Befund:** Drei Stellen pro Edit berücksichtigen müssen — Quick-Index (Tabelle), TP-Abschnitt, Ist-Stand-Block. Keine schlägt die andere. Wer eine ändert, **muss** die anderen mitlesen. Die Datei hat aktuell 1940 Zeilen, der Ist-Stand-Block steht bei Z. 28, das Archiv-Cover bei Z. 1771. Strukturelles Risiko, kein Einzelfall.
|
||||
- **Scope (Skizze, eigene Session):**
|
||||
1. **Nautobot Custom Fields für Live-Daten** — RouterOS-Version, Compliance-Zahl (104/104, 26 Rules × 4 Geräte), DHCP-Server-Anzahl, MGMT-IPs, DNS-Upstream-Modus. Script `nautobot/gc-snapshot.py` rendert `docs/teilprojekte.md` (oder einen schmaleren Ersatz) als **read-only Snapshot**.
|
||||
2. **Datei-Aufteilung** — `docs/teilprojekte-index.md` (1 Seite: nur aktive TPs, Titel + Status + Datum), `docs/teilprojekte-aktuell.md` (Live-Snapshot aus Nautobot), `docs/teilprojekte-archiv.md` (bleibt Volltext). `/projektstatus`-Skill liest Index + Archiv, nicht die Snapshot-Datei.
|
||||
3. **Archiv-Anzeige im Quick-Index** — die heute 34 Namen stehen heute in *einer* Zeile am Ende. Sichtbarkeit = „Geschichte zählt". Quick-Index-Block bekommt eine zweite Tabelle mit „abgeschlossen seit …" und Link aufs Archiv.
|
||||
4. **Migrationspfad** — kompatibel mit bestehendem Workflow (`/projektstatus`-Skill konsumieren, niemand außer mir editiert Live-Markdown). Testphase = beide Dateien parallel führen.
|
||||
- **Abgrenzung:** TP36 ist Querschnitt, nicht Kern-BF. Eigene Session, eigener Handoff. Nicht heute.
|
||||
- **Verzahnt mit:** TP22 (Nautobot-GC als Vorbild), TP35 (geht Hand in Hand — beide sind „SSoT + Konsolidierung"), `bf-infra/CLAUDE.md`-Lessons.
|
||||
- **Referenzen:** Lessons-Block-Eintrag „Manuell gepflegte Doku mit Live-Daten verliert gegen die Realität" · Handoff Session A 2026-08-28.
|
||||
### TP36 — Index/Status als SSoT nach Gitea (Steuerung aus der branchbaren Datei herauslösen) ▸ ⏳ **CUTOVER 2026-09-07** — Index/Status = Gitea-Issues, Prosa bleibt Datei
|
||||
- **Auslöser:** Skill-Run 2026-08-28 (`docs/handoff-20260828-session-a-projektstatus.md`) lieferte einen überholten „Nächster Schritt"-Output; **manuell gepflegte Doku mit Live-Daten verliert gegen die Realität, sobald sie lang wird.** Verschärft 2026-09-06: `docs/teilprojekte.md` wurde in **40/40** letzten Commits angefasst — jeder TP editierte Quick-Index **und** Ist-Stand-Block → **Merge-Konflikt-Magnet**, der Branch-pro-TP verhinderte (ein Parallel-Branch hatte so die TP37-Doppelvergabe verursacht).
|
||||
- 🔄 **Reframe 2026-09-06 (Christoph):** von „SSoT via **Nautobot**" auf „SSoT via **Gitea**". Grund: Index+Status sind **kuratierte Steuerung** (Reihenfolge, Marker, Abhängigkeiten), kein Geräte-Live-Zustand — die gehören auf ein **Issue-Board**, nicht in Custom Fields. **Nautobot bleibt nur für Live-Gerätedaten** relevant (Compliance-Zahl, RouterOS-Version …) → als optionaler Rest unten, entkoppelt von diesem TP.
|
||||
- **Modell (umgesetzt):** TP = **Gitea-Issue** in [`admin/bf-infra`](https://gitea.emsenhuber.net/admin/bf-infra/issues) · Status = Label `status:*` (todo/wip/paused/idea/concept/done/dropped) · Gruppierung = Label `thema:*`. Seeder `bin/gitea-tp-sync.py` (idempotent, Dry-Run default, `--commit` schreibt; Token aus `~/.hermes/.env`, **nie ausgeben**). Erstlauf: **68 Issues (25 open/43 closed) + 15 Labels**.
|
||||
- ✅ **Erledigt (A1–A3):** Labels/Modell · 68 TPs → Issues · Board = Index (Label-Filter statt Handtabelle).
|
||||
- ⏳ **Cutover 2026-09-07 (diese Session):**
|
||||
- **A4** — Quick-Index-Tabelle + „Ist-Stand (Kurz)"-Block aus dieser Datei entfernt; Header zeigt aufs Gitea-Board; die vier **Genehmigten Ausnahmen** unter eigenem Governance-Header behalten. Alle `### TPnn`-Prosa bleibt.
|
||||
- **A5** — `/projektstatus` liest Baum+Status aus der **Gitea-API** (Issues + `status:*`/`thema:*`), Transaktionen weiter aus `nautobot/gc-transaktion.py status`, Prosa-Detail bei Bedarf aus dem Repo. Beide Skill-Kopien (`~/.claude/skills/…` **und** `~/.config/opencode/skills/…`, `cp`, kein Symlink).
|
||||
- **A6** — Projekt-`CLAUDE.md`: Pflichtlektüre = Gitea-Board (Status) + Prosa-Datei (Detail); Branch-Konvention (`tpNN-kurz` jederzeit, Merge nach `main` wenn Code/Config steht, Steuerungs-Updates nach Gitea); SSoT-Notiz.
|
||||
- 🔜 **Optionaler Rest (entkoppelt, „TP36-Live"):** Live-Daten-CustomFields auf den **4 `dcim.Device`** (`ros_version`, `compliance_pct`, `dhcp_server_count`, `mgmt_ip`, `dns_upstream_mode`) + Snapshot-Skript `nautobot/gc-snapshot.py` (existiert noch nicht). Unabhängig von diesem Cutover; nur relevant, wenn die Doku Live-Zahlen tragen soll. ⚠️ **Namensfalle bereinigt:** `nautobot/tp36-cf-estate-seed.py` gehörte **nie** zu TP36 → seit 2026-09-06 `tp44-cf-estate-seed.py`.
|
||||
- **Verzahnt mit:** TP35 (SSoT + Konsolidierung), TP44 (native Nautobot-Modelle), `bf-infra/CLAUDE.md`-Lessons. Plan: `~/.claude/plans/geht-das-los-auch-reflective-lark.md`.
|
||||
|
||||
<a id="tp37"></a>
|
||||
### TP38 — Out-of-Band-Management: ein untagged-VLAN99-Port je Switch ▸ 🔜 **ANGELEGT 2026-08-31**
|
||||
@@ -2585,6 +2460,47 @@ folgenden Absicherungen dazu, und die Entscheidung darüber in die Umsetzungs-Se
|
||||
|
||||
---
|
||||
|
||||
### TP40 — Home-Assistant-Recorder-Retention: die 41-GB-`states`-Tabelle beschneiden ▸ 🔜 **ANGELEGT 2026-09-01 (User-Okay erteilt)**
|
||||
|
||||
**Auslöser:** LXC 302 (MariaDB) lief am 2026-09-01 auf **100 %** voll. Sofortmassnahme war `+30G`
|
||||
(TP39 Punkt 3), aber 59 der 65 GB sind die **`homeassistant`-Datenbank**, und die wächst weiter —
|
||||
`+30G` verschiebt das Problem um ~4 Wochen, es löst es nicht.
|
||||
|
||||
#### Befund (live gemessen)
|
||||
|
||||
| Tabelle | Größe |
|
||||
|---|---|
|
||||
| `homeassistant.states` | **41 GB** |
|
||||
| `homeassistant.state_attributes` | 8,6 GB |
|
||||
| `homeassistant.statistics_short_term` | 8,1 GB |
|
||||
| `homeassistant.statistics` / `events` | je ~0,7 GB |
|
||||
|
||||
Der HA-Recorder schreibt **unbegrenzt** — es ist keine `purge_keep_days`-Grenze wirksam, sonst wäre
|
||||
`states` nicht auf 41 GB gewachsen. Das ist ein Konfigurations-, kein Plattenproblem.
|
||||
|
||||
#### Scope
|
||||
|
||||
1. **HA-`recorder`-Retention setzen** (`configuration.yaml` bzw. `.storage`): `purge_keep_days`
|
||||
auf einen bewussten Wert (Vorschlag 30) — **Christoph entscheidet die Zahl**, das ist eine
|
||||
Aufbewahrungs-Policy, keine rein technische Größe.
|
||||
2. **Rauschende Entities ausschließen** (`recorder: exclude`) — die üblichen Verdächtigen sind
|
||||
hochfrequente Sensoren (Leistung, Netz-Durchsatz, `sensor.time`/`date`). Vorher per
|
||||
`SELECT COUNT(*) … GROUP BY entity_id` die Top-Schreiber ermitteln, nicht raten.
|
||||
3. **`recorder.purge` mit `repack: true`** — erst nach 1+2, sonst wächst es sofort nach. `repack`
|
||||
gibt den Plattenplatz auf InnoDB-Ebene **real** frei (ohne repack bleibt die `.ibd`-Datei gross).
|
||||
🔴 **`states` hängt per FK an `state_attributes` und `events`** — purge räumt beide mit; die
|
||||
Reihenfolge macht HA selbst, **nicht** von Hand einzelne Tabellen truncaten.
|
||||
4. **Danach die TP39-Vergrösserung bewerten:** schrumpft `states` deutlich, waren die `+30G`
|
||||
Vorhalt und keine Dauerlösung — die Platte lässt sich zwar nicht online verkleinern, aber der
|
||||
Druck ist weg.
|
||||
|
||||
#### Abgrenzung
|
||||
|
||||
- **Nicht** TP39: das ist LXC-/DB-Hygiene (Resolver, `networking`, `skip-name-resolve`). Der
|
||||
Resize tauchte dort nur auf; die **Ursache** (HA-Retention) ist HA-seitig und darum ein eigenes TP.
|
||||
- 🔴 **Kein eigenmächtiger Datenlöschvorgang** — `purge` wirft echte Historie weg; die
|
||||
Aufbewahrungsdauer ist eine Nutzerentscheidung. Diese Session hat **nur** vergrössert und gemessen.
|
||||
|
||||
### TP37 — Nautobot als durchgehende Netzwerkdoku: Hosts/Container/Dienste, erster Anwendungsfall CF-Connectoren ▸ 🔜 ANGELEGT 2026-08-30 (User-Okay erteilt)
|
||||
> **Christophs Formulierung (2026-08-30):** *„können wir das setup mit den cf-connectoren dann auch in
|
||||
> nautobot abbilden. quasi eine durchgehende netzwerkdoku stück für stück. muss eh fast sein, da du auf
|
||||
@@ -2609,10 +2525,10 @@ folgenden Absicherungen dazu, und die Entscheidung darüber in die Umsetzungs-Se
|
||||
„wo läuft was" steht.
|
||||
2. **Dienste abbilden** — `ipam.Service` je exponiertem Port (Caddy `:80/:443`, AdGuard `:53`,
|
||||
Nautobot `:8080`, n8n `:5678`, …). Das ist Nautobot-Kernmodell, **keine eigene App nötig**.
|
||||
3. **CF-Connectoren als erster Anwendungsfall** — Tunnel (`bf-public`, historisch `bf-mm`/`bf-nas`/`bf-pve`)
|
||||
als Objekt, Connector als Relation Tunnel↔Host, Ingress-Regel als Hostname→Backend-Paar.
|
||||
Modellwahl offen: Custom Fields + Relationships auf Bestandsmodellen **oder** eine kleine eigene App.
|
||||
🔴 **Erst Punkt 1–2 entscheiden, dann diese Frage** — umgekehrt entsteht ein Modell für einen Sonderfall.
|
||||
3. ✅ **CF-Connectoren — ERLEDIGT via [TP44](teilprojekte-archiv.md#tp44) (Etappe 1, 2026-09-02).** Die Modellwahl ist damit
|
||||
entschieden: **native `nautobot.cloud`-Modelle** (Tunnel/WARP = `CloudNetwork`, VPC/Hyperdrive/Worker/
|
||||
Access-App = `CloudService`, IDs/Ports/Origins in `extra_config`), **keine eigene App**. Offen nur noch
|
||||
TP44 Etappe 2 (CF-API→Nautobot-Sync). ⇒ **Punkt 1+2 unten sind der echte Rest von TP37.**
|
||||
4. **Drift-Check** — Skript liest CF-API (`cfd_tunnel` + `configurations`) und vergleicht gegen Nautobot,
|
||||
analog `nautobot/gc-configplan.py --refresh-compliance`. **Read-only zuerst**; ob Nautobot je nach
|
||||
Cloudflare *schreibt*, ist eine spätere, eigene Entscheidung.
|
||||
@@ -2630,7 +2546,11 @@ folgenden Absicherungen dazu, und die Entscheidung darüber in die Umsetzungs-Se
|
||||
die Pipeline ist stabil und **104/104 compliant**. TP37 vergrößert die Angriffsfläche dieser Pipeline.
|
||||
Deshalb Punkt 1–2 als eigener, abnehmbarer Schritt **mit Compliance-Gegenprobe danach**, nicht als
|
||||
Nebeneffekt von Punkt 3.
|
||||
- **Status:** 🔜 angelegt 2026-08-30, Scope-Ausarbeitung in eigener Session. Kein Runbook.
|
||||
- **Status:** ⏳ **Punkt 3 (CF) ✅ via TP44; Punkt 1+2 (Substrat + Dienste) offen** — das ist die
|
||||
fehlende Voraussetzung für TP34. Datenmodell **entschieden 2026-09-06 (native Modelle:
|
||||
`virtualization.Cluster/VirtualMachine` + `ipam.Service`, keine App)**. Runbook liegt jetzt vor:
|
||||
[`handoff-20260906-tp37-34-36-plan.md`](handoff-20260906-tp37-34-36-plan.md). Live-Ausgangslage:
|
||||
VM 0 · Cluster 0 · `ipam.Service` 0 · CustomField 0 (2026-09-06 gegen die API gelesen).
|
||||
|
||||
---
|
||||
|
||||
@@ -2650,7 +2570,7 @@ Kurzorientierung, wo was zu finden ist:
|
||||
| **Firewall / QoS** | [TP5](teilprojekte-archiv.md#tp5) deny-by-default · [TP26](teilprojekte-archiv.md#tp26) `ip-firewall-filter` unter Drift-Kontrolle · [TP6](teilprojekte-archiv.md#tp6) CAKE *(geschlossen statt gebaut)* · [TP6.1](teilprojekte-archiv.md#tp6-1) Upload-Priorisierung |
|
||||
| **Discovery / Media** | [TP7](teilprojekte-archiv.md#tp7) mDNS · [TP7.1](teilprojekte-archiv.md#tp7-1) SSDP-Relay · [TP7.2](teilprojekte-archiv.md#tp7-2) HA↔Sonos |
|
||||
| **Hosts / Migration** | [TP14](teilprojekte-archiv.md#tp14) (+[.1](teilprojekte-archiv.md#tp14-1)/[.2](teilprojekte-archiv.md#tp14-2)/[.2a](teilprojekte-archiv.md#tp14-2a)/[.3](teilprojekte-archiv.md#tp14-3)/[.5](teilprojekte-archiv.md#tp14-5)) VLAN20-Cutover · [TP17](teilprojekte-archiv.md#tp17) Shelly→VLAN30 · [TP19](teilprojekte-archiv.md#tp19) VLAN1-Retirement |
|
||||
| **Control-Plane** | [TP20](teilprojekte-archiv.md#tp20) Platform-Postgres · [TP21](teilprojekte-archiv.md#tp21) Nautobot GC · [TP22](teilprojekte-archiv.md#tp22) Adoption + Compliance-Push · [TP27](teilprojekte-archiv.md#tp27) RouterBOOT 7.24 · [TP-R](teilprojekte-archiv.md#tp-r) Capabilities-Sweep |
|
||||
| **Control-Plane** | [TP20](teilprojekte-archiv.md#tp20) Platform-Postgres · [TP21](teilprojekte-archiv.md#tp21) Nautobot GC · [TP22](teilprojekte-archiv.md#tp22) Adoption + Compliance-Push · [TP27](teilprojekte-archiv.md#tp27) RouterBOOT 7.24 · [TP-R](teilprojekte-archiv.md#tp-r) Capabilities-Sweep · [TP44](teilprojekte-archiv.md#tp44) CF-Estate Doku-SSoT |
|
||||
| **Zugang** | [TP10](teilprojekte-archiv.md#tp10) Multi-Site-VPN *(offen nur der DDNS-Updater, s. Follow-ups)* · [TP16.1](teilprojekte-archiv.md#tp16-1) natives CF-Mesh |
|
||||
| **Verworfen** | [TP9](teilprojekte-archiv.md#tp9) Gateway-HA (User-Entscheid 2026-08-08) |
|
||||
|
||||
@@ -2805,3 +2725,78 @@ TP22 · TP-R · **TP3.2** (08-17) · **TP5** (08-18) · **TP7.1** (08-18) · **T
|
||||
7. **Foundation (2026-07-14):** **TP15** (MikroTik-Switching / Omada-WLAN, 2× CRS326 bestellt) ∥ **TP20 (Platform-Postgres, single-site replication-ready)** → **TP21 (Nautobot Golden Config)** ∥ **TP20.1 (Vaultwarden→PG + 2-Site-HA)**. TP20 hängt an **TP18 ①** (Garage-Bucket für pgBackRest).
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### TP43 — dw-Standort: interne BF-DNS-Namen über WG auflösbar machen ▸ ✅ **UMGESETZT 2026-09-11** — dw-FritzBox: Upstream `.36`+`.37`, DNS-Rebind-Ausnahme `bf.emsenhuber.net`, Fallback-Haken „öffentliche NS bei Unreachbarkeit" **gesetzt** (Ideal-Variante: `.37`-Redundanz bleibt, BF-down → public). (verworfene 420-Historie am Ende dieses Abschnitts)
|
||||
|
||||
**Live-Auslöser (2026-09-11):** Christoph am dw-Standort, WG-Tunnel zu BF up, kann `portainer.bf.emsenhuber.net`
|
||||
nicht erreichen. Direkte IP `https://10.40.20.126:9443` geht ⇒ **reines DNS-, kein Routing-Problem.** Der
|
||||
dw-Client nutzt die FritzBox (`10.95.10.1`) als Resolver; die kennt die interne Zone `bf.emsenhuber.net`
|
||||
(Split-Horizon `.36/.37 → 10.40.20.40` Caddy) nicht.
|
||||
|
||||
**Korrektur gegenüber dem verworfenen Scope:** Der ursprüngliche Fall (`420.teilzeitladen.xyz`) ist ein
|
||||
**öffentlicher** CF-Worker und war nie das Problem — der ist via TP41/WARP + CF Access gelöst. Das echte,
|
||||
offene Problem sind **interne** BF-Namen (`*.bf.emsenhuber.net`) über den WG-Tunnel.
|
||||
|
||||
**Live verifiziert (2026-09-11, `dig @10.40.20.36` über den Tunnel):** `portainer.bf.emsenhuber.net
|
||||
→ 10.40.20.40` (Caddy), `macmini.bf.emsenhuber.net → 10.40.20.167` — alle internen bf-Namen landen
|
||||
in `10.40.0.0/16`, über WG erreichbar. `ds-fm`/`gateway-fm.emsenhuber.net → 188.114.96.10/.97.10`
|
||||
= **Cloudflare-Anycast** (public), **nie `10.101.0.x`**. ⇒ **Der fm-Einwand (10.101.x intern ohne
|
||||
Pfad von dw) trifft für `.36/.37` nicht zu** — fm läuft über den public `fm.emsenhuber.net`-Tunnel,
|
||||
nicht über interne Records. (WG-Topologie TP10: dw-Peer AllowedIPs BF-seitig = `10.40.0.0/16`, dw
|
||||
routet **nicht** nach `10.101.0.0/24`.)
|
||||
|
||||
**Constraint am dw:** die 24/7-Geräte `10.95.10.246/.247` sind **Cudy-APs (kein DNS-Host)**; die
|
||||
FritzBox kann **kein Per-Zone-Forwarding** (nur einen globalen Upstream) **und per DHCP nur EINE
|
||||
DNS-IP ausliefern** (⇒ „mehrere NS an die Clients" scheidet aus). Ein echter conditional forwarder
|
||||
(dnsmasq `server=/bf.emsenhuber.net/.36`) bräuchte einen Zusatz-Dauerläufer — abgelehnt.
|
||||
|
||||
**Entscheidung (Christoph, 2026-09-11): FB-Upstream + Rebind-Ausnahme.** Clients bekommen per DHCP
|
||||
`10.95.10.1` (die FB selbst, Default); die **FB forwardet an die BF-Resolver**: *DNS-Server → „Andere
|
||||
DNSv4-Server"* Bevorzugt **`10.40.20.36`**, Alternativ **`10.40.20.37`** (beide BF, beide
|
||||
Voll-Resolver → Redundanz bleibt). Sauberer als der zwischenzeitliche DHCP-Multi-Gedanke: die FB ist
|
||||
der **einzige** Client-Resolver und `.36` löst **intern und public** auf → alles geht zuerst an `.36`,
|
||||
public wird nur als Unreachable-Fallback konsultiert, **nie „zuerst"** → kein NXDOMAIN-Leak im
|
||||
Normalbetrieb.
|
||||
|
||||
🔴 **DNS-Rebind-Schutz-Ausnahme `bf.emsenhuber.net`** (*Heimnetz → Netzwerk → Netzwerkeinstellungen →
|
||||
DNS-Rebind-Schutz*) ist **zwingend**: sonst filtert die FB die Privat-IP-Antworten (`10.40.x`) als
|
||||
Rebind-Angriff weg → bf-Namen liefern nichts, obwohl `.36` korrekt antwortet. Die Ausnahme ist ein
|
||||
reines Namens-Whitelist (keine IP).
|
||||
|
||||
**BF-down-Fallback (Verzweigung am FRITZ!OS-Stand):** Christoph erinnert ein Setting „öffentliche NS
|
||||
verwenden, wenn die primären nicht erreichbar sind". Vorhanden → aktivieren, Upstream bleibt
|
||||
`.36`+`.37`, BF-down geht auf public. Fehlt → Alternativ-Slot statt `.37` auf **public `9.9.9.9`**
|
||||
(kostet `.37`-Redundanz); dann zusätzlich prüfen, dass die FB **strikt primär** fragt (nicht
|
||||
round-robbt), sonst NXDOMAIN-Leak für `bf.*` bei BF-up.
|
||||
|
||||
- **BF-up:** FB → `.36` → interne `bf.*` (→ `.40`, dank Rebind-Ausnahme durchgereicht) **und** public.
|
||||
- **BF-down:** `.36`/`.37` unreachable → public-Fallback → public lebt, `bf.*` = NXDOMAIN (erwartet).
|
||||
|
||||
**Bewusst akzeptierter Tradeoff:** bei BF-up läuft Geli's **gesamter** Haushalt-DNS über Linz
|
||||
(`.36`/AdGuard-Filter) — vermeidbar nur mit conditional forwarder (Zusatz-HW, abgelehnt).
|
||||
|
||||
**On-site-Verifikationen (Christoph, am dw):** (1) Rebind-Ausnahme greift — `nslookup
|
||||
portainer.bf.emsenhuber.net` über die FB → stabil `10.40.20.40`; (2) BF-down-Fallback vorhanden
|
||||
(Setting) oder via public-Alternativ-Slot gesetzt; (3) nur falls BF+public gemischt: FB fragt strikt
|
||||
primär. Rückfall pro Gerät: `/etc/hosts` `10.40.20.40 <name>` oder WARP `fallback_domains
|
||||
bf.emsenhuber.net → [.36,.37]` (TP41-Präzedenz).
|
||||
|
||||
**Sofort-Workaround (läuft unabhängig):** `https://10.40.20.126:9443` direkt bzw.
|
||||
`/etc/hosts`-Zeile `10.40.20.40 portainer.bf.emsenhuber.net`.
|
||||
|
||||
**Abhängigkeiten:** WG-Route dw→`10.40.0.0/16` (steht). Grenzt an TP42 (interner Namensraum
|
||||
`bf.emsenhuber.net`) und TP10 (Multi-Site-VPN). **Umsetzung = eigene On-site-Session** (FritzBox-DHCP
|
||||
ist Christophs manueller Schritt, kein Tool-Zugriff).
|
||||
|
||||
---
|
||||
|
||||
**Historie — verworfener 420-Scope (angelegt 2026-09-01, verworfen 2026-09-11):**
|
||||
|
||||
**Auslöser (2026-09-01, TP41-Follow-up):** Geli soll `420.teilzeitladen.xyz` am dw-Standort erreichen.
|
||||
Split-Horizon am dw scheitert an der **FritzBox** (`10.95.10.1`): kein Per-Host-A-Override im Standard
|
||||
(nur DNS-Rebind-Ausnahmen ohne IP). Christoph: *„keine Chance im FritzBox-Standard? … lieber ein TP als
|
||||
uns verfranzen. Geli kommt rein, das zählt."* — Diese Prämisse fiel weg: `420.teilzeitladen.xyz` ist ein
|
||||
public CF-Worker hinter CF Access (löst auf CF-Anycast), kein BF-Origin ⇒ dafür braucht es kein
|
||||
Split-Horizon; Zugang via TP41-**WARP** gelöst (Geli 2026-09-10 via Android). Der Override-Bedarf für
|
||||
**interne** Namen blieb dabei übersehen — deshalb reopened, s.o.
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
> **§1–§3 AUSGEFÜHRT 2026-08-31.** Drei Connectoren laufen, `bf-public` healthy/12.
|
||||
> §2.2, §3.4 und §3.5 sind unten **korrigiert** — die ursprüngliche Fassung war an drei
|
||||
> Stellen falsch (Flash-Budget, `docker save`-Format, `envs`-Parametername).
|
||||
> Offen bleiben **§5 (Flip)** und **§6 (Abbau)**.
|
||||
> ✅ **§5 (Flip) AUSGEFÜHRT 2026-09-01** — alle vier Namen auf `bf-public`.
|
||||
> Offen bleibt nur **§6 (Abbau)**.
|
||||
> **Löst [`tp31-schritt5-runbook.md`](tp31-schritt5-runbook.md) ab** (Stand 08-27). Jenes Dokument
|
||||
> kennt ap3 nicht, unterstellt einen Registry-Pull (geht bei `fetch: no` nicht) und enthält **eine
|
||||
> nachweislich falsche Freigabe-Behauptung** (§8 Falle 2). Es bleibt als Historie liegen, ist aber
|
||||
@@ -398,6 +399,10 @@ wie es war. Dann einfach neu absetzen.
|
||||
Das `masquerade` ist **Pflicht**, nicht Kosmetik — siehe §1.2: ohne es kommen die Pakete mit
|
||||
`172.17.0.2` am Core an, wo weder Route noch Firewall-Regel sie kennt.
|
||||
|
||||
✅ **Seit 2026-08-31 stehen diese drei Zeilen im SOLL** (AP-Template Block `[7]`, Werte aus dem
|
||||
ConfigContext `ap-common` → `ap.container`). Wer sie hier direkt setzt, erzeugt daher **keine
|
||||
Drift mehr** — aber auch keinen Bedarf: bei einem neuen AP rendert Golden Config sie mit.
|
||||
|
||||
### 3.5 Image importieren und Container bauen
|
||||
|
||||
```bash
|
||||
@@ -487,7 +492,7 @@ für die Strecke bis Caddy ist §5.1, nicht diese Zahl. Genau diese Verwechslung
|
||||
|
||||
---
|
||||
|
||||
## §5 CNAME-Flip — einzeln, mit Abnahme dazwischen
|
||||
## §5 CNAME-Flip — ✅ **AUSGEFÜHRT 2026-09-01** (einzeln, mit Abnahme dazwischen)
|
||||
|
||||
**Reihenfolge: `n8n` → `gitea` → `hass` → `vw`** (steigende Kritikalität; `vw` zuletzt).
|
||||
Zone-ID `1b5bc02fdf61b6b989afde543f3f4134`.
|
||||
@@ -503,7 +508,20 @@ curl -s -X POST -H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: appli
|
||||
```
|
||||
Dazu **eine Ingress-Regel** für `test-tp163.emsenhuber.net` → `https://10.40.20.40:443` mit
|
||||
`originServerName: vw.emsenhuber.net` in `bf-public` ergänzen. Dann **von außerhalb des LAN, ohne
|
||||
WARP** aufrufen. Erwartet: Access-Login, **keine Redirect-Schleife**.
|
||||
WARP** aufrufen.
|
||||
|
||||
🔑 **Das Erfolgskriterium ist praeziser, als es hier bis 2026-08-31 stand — und die frühere Fassung
|
||||
war zweideutig.** Gemessen am 2026-08-31 gegen `10.40.20.40`:
|
||||
|
||||
| Antwort | Bedeutung |
|
||||
|---|---|
|
||||
| Access-Login, danach **`200` mit LEEREM Body** und Header **`server: Caddy`** | ✅ **Strecke bewiesen.** Caddy hat geantwortet; es gibt für `test-tp163` nur kein Site-Block, und genau so antwortet Caddy auf einen unbekannten Host. |
|
||||
| **`404`** | ❌ Die Ingress-Regel greift nicht — das ist der **Catch-all** von `bf-public` (`http_status:404`). |
|
||||
| **`ERR_TOO_MANY_REDIRECTS`** | ❌ Blocker A ist zurück (Ingress auf `:80` oder `originServerName` fehlt). Sofort abbrechen. |
|
||||
|
||||
⚠️ **Ohne diese Tabelle liest man das leere 200 als „kaputt" und das 404 als „Caddy sagt nichts" —
|
||||
beide Male falsch herum.** Der zweite, unabhängige Beweis ist immer das Caddy-Log (§5.3).
|
||||
|
||||
⇒ Erst wenn das steht, wird ein Produktivname angefasst. Danach Testname + Testregel wieder entfernen.
|
||||
|
||||
### 5.2 Flip je Name
|
||||
@@ -523,9 +541,29 @@ curl -s -X PATCH -H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: appl
|
||||
|
||||
- [ ] Aufruf über Mobilfunk (oder anderer Standort) → Access-Login → **200**
|
||||
- [ ] **Kein** `ERR_TOO_MANY_REDIRECTS` (das wäre Blocker A)
|
||||
- [ ] Caddy sieht den Request: `ssh root@10.40.20.100 'pct exec 130 -- journalctl -u caddy -n 20'`
|
||||
- [ ] 15 min beobachten, kein 530/1033
|
||||
|
||||
🔴 **KORRIGIERT 2026-09-01 — der frühere Punkt „Caddy sieht den Request:
|
||||
`journalctl -u caddy -n 20`" funktioniert NICHT.** Im `Caddyfile` steht keine `log`-Direktive; im
|
||||
Journal landen nur `info`/`warn`. Ein **erfolgreicher** Request hinterlässt dort **nichts**, und die
|
||||
leere Ausgabe liest sich wie „kam nie an". *(Dass der öffentliche Reverse Proxy überhaupt keine
|
||||
Requests protokolliert, ist eine eigene Lücke — gehört zu TP31/TP34.)*
|
||||
|
||||
**Was stattdessen funktioniert — und 2026-09-01 auch benutzt wurde:**
|
||||
|
||||
| Werkzeug | Beweist |
|
||||
|---|---|
|
||||
| `curl --resolve <name>:443:188.114.96.10` | Erzwingt den **öffentlichen** Weg. 🔴 **Pflicht**, denn der Haus-Resolver liefert für alle vier Namen direkt `10.40.20.40` (Split-Horizon) — ein Test von zuhause sieht Cloudflare **nie**. |
|
||||
| Verbindungstabelle am Core (`/ip firewall connection`) | Zeigt `10.40.99.x → 10.40.20.40` = ein AP-Connector redet mit Caddy. **Der Zähler der Blocker-B-Regel taugt dafür NICHT**: `cloudflared` hält die Origin-Verbindung offen, es entstehen kaum neue — der Zähler steht still, obwohl alles läuft. |
|
||||
| Antwort-Fingerabdruck | z.B. `i_like_gitea`-Cookie = echte Gitea-Antwort, nicht CF/Caddy. |
|
||||
| WebSocket-Handshake **mit `--http1.1`** | `101 Switching Protocols` = der Companion-App-Pfad steht. ⚠️ Über HTTP/2 gibt es keinen klassischen Upgrade — ein `400` ist dann der eigene Testfehler, nicht der Dienst. |
|
||||
|
||||
⚠️ **Access antwortet je nach Standort verschieden, beides gesund:** `n8n` liefert aus dem Haus
|
||||
**200** (die `bf4`-Policy trägt die WAN-IP), von außen **302** zum Login. `hass`/`vw`/`gitea` stehen
|
||||
auf **`bypass`** (App `hass, vw, gitea`, alle drei in `self_hosted_domains`) — dort kommt **nie** ein
|
||||
Login. Ein Service-Token für die Wildcard-App gibt es nicht (**TP14.4**), deshalb ist `n8n` von außen
|
||||
**nicht** bis zum Origin prüfbar — das musste der User im Browser bestätigen.
|
||||
|
||||
🔴 **WARP muss aus sein.** Mit aktivem WARP läuft der Test über den Mesh und beweist den öffentlichen
|
||||
Weg **nicht** — dieselbe Klasse Fehldiagnose wie beim ICMP-Fall 2026-08-13.
|
||||
|
||||
@@ -539,7 +577,14 @@ Weg **nicht** — dieselbe Klasse Fehldiagnose wie beim ICMP-Fall 2026-08-13.
|
||||
|
||||
---
|
||||
|
||||
## §6 Abbau — **frühestens nach 7 Tagen störungsfreiem Betrieb**
|
||||
## §6 Abbau — ✅ **AUSGEFÜHRT 2026-09-01** (7-Tage-Frist vom User aufgehoben)
|
||||
|
||||
> ✅ **Durch.** 7 Container entfernt (inkl. `terpene-cloudflared`, weil `420.teilzeitladen.xyz` nun
|
||||
> über Caddy/CF läuft — vor der Tunnel-Löschung mit echtem Origin-Inhalt belegt), 4 Tunnel gelöscht
|
||||
> (`bf-mm`/`bf-nas`/`bf-pve`/`terpene-db`). Übrig: nur `bf-public` + `fm`. Reihenfolge Container→Tunnel
|
||||
> eingehalten. Der Rest dieses Abschnitts bleibt als Referenz stehen.
|
||||
|
||||
### (Original-Anleitung, Referenz)
|
||||
|
||||
> Die drei Alttunnel sind die Rückfallebene. Solange sie stehen, ist jeder Flip eine
|
||||
> Ein-Feld-Änderung zurück. **Nicht am selben Abend abbauen.**
|
||||
@@ -639,12 +684,23 @@ physischem Gang. Es schadet nicht — ohne laufenden Container ist es ein gesetz
|
||||
12. 🔴 **`docker save` liefert seit Docker 25 OCI statt docker-v1** → `no config found in manifest`.
|
||||
13. 🔴 **`/container/envs` nimmt `list=`, nicht `name=`.**
|
||||
14. 🔴 **Der `device-mode`-Bestätigungs-Boot installiert keine Pakete** — Reihenfolge s. §3.3.
|
||||
15. 🔴 **§3.4 kollidiert mit der GC-Governance:** `ip address` und `ip firewall nat` stehen unter
|
||||
Drift-Kontrolle. Direkt gesetzt ⇒ **zwei `extra`-Drifts je AP**. Entweder vorher ins Soll heben
|
||||
(AP-Template/ConfigContext) oder die Drift bewusst als offene Transaktion führen.
|
||||
16. 🟡 **`A - AVAILABLE` in `/system package print` ist ein Download-Katalog**, kein Paket auf dem
|
||||
15. ✅ **ERLEDIGT 2026-08-31 — §3.4 kollidierte mit der GC-Governance:** `ip address` und
|
||||
`ip firewall nat` stehen unter Drift-Kontrolle, direkt gesetzt ergab das **zwei `extra`-Drifts
|
||||
je AP**. Sie sind jetzt **ins Soll gehoben** (AP-Template Block `[7]` + ConfigContext
|
||||
`ap.container`), **nicht** als Transaktion geführt: ein Dauerzustand gehört ins Template.
|
||||
Dazu kam die **28. ComplianceRule `interface-veth`** — vorher war das veth das tragende Stück
|
||||
**ohne jede Überwachung**. 🔴 **Falle darin:** der veth-Export trägt zwei gerätevergebene MACs;
|
||||
ohne Normalisierung (`ConfigReplace` `60-`/`61-veth-*`) erzeugt die Regel Dauer-Drift auf allen
|
||||
drei APs. Stand danach: **139/140**, übrig nur die offene TP25-Transaktion.
|
||||
16. 🔴 **Ein Golden-Config-Job meldet `SUCCESS` und kann trotzdem halb durchgelaufen sein.**
|
||||
Am 2026-08-31 fehlte nach dem ersten Compliance-Lauf genau **ein** Eintrag
|
||||
(`crs326-core`/`interface-veth`), Job-Status `SUCCESS`, im Job-Log dagegen
|
||||
`RENDER COMPLIANCE TASK GROUP failed: Broken pipe`. **Abnahme ist deshalb nicht die
|
||||
Konformitätsquote, sondern die ANZAHL der Einträge = Regeln × Geräte.** 139 statt 140 sieht
|
||||
aus wie „die neue Regel greift nicht" und ist ein halb gelaufener Job. Zweiter Lauf reichte.
|
||||
17. 🟡 **`A - AVAILABLE` in `/system package print` ist ein Download-Katalog**, kein Paket auf dem
|
||||
Gerät — `enable` würde einen Internet-Fetch auslösen (auf ap1/ap2 gesperrt). `.npk` bleibt der Weg.
|
||||
17. 🟡 **MikroMCPs `export_config` exportiert unvollständig** (301 B statt 6,2 KiB). Für Backups
|
||||
18. 🟡 **MikroMCPs `export_config` exportiert unvollständig** (301 B statt 6,2 KiB). Für Backups
|
||||
`/export file=…` per SSH verwenden. Nach zwei
|
||||
Reboots je AP lohnt der Blick — die Tabelle zeigte beim CAPsMAN-Ausfall 14 h lang zufriedene
|
||||
Clients ohne Adresse.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Übergabeprompt — TP16.3 §5: CNAME-Flip auf `bf-public`
|
||||
|
||||
> **Zum Einfügen in eine frische Session.** Erstellt 2026-08-31, direkt nach §2/§3.
|
||||
> Live-Stand am 2026-08-31 gegengeprüft: 12 Connectoren, drei Container `running`,
|
||||
> Caddy mit SNI 200 / ohne SNI 000.
|
||||
> Alles unterhalb der Linie ist der Prompt.
|
||||
|
||||
---
|
||||
@@ -17,6 +19,12 @@ frühestens 7 Tage nach dem Flip.
|
||||
2. `docs/tp16.3-bf-public-ap-connector-runbook.md` **§5** (und §7 Rollback)
|
||||
3. `docs/teilprojekte.md` (Quick-Index + Ist-Stand + TP16.3-Abschnitt)
|
||||
|
||||
## REPO-STAND
|
||||
|
||||
Alles liegt auf **`main`** (`e474e5e`, Gitea `admin/bf-infra`) — Haupt-Checkout, Remote und der
|
||||
Arbeitsbranch der Vorsession sind identisch. **Von `main` aus starten**, nichts mehr mergen.
|
||||
Die Vorsession lief im Worktree `claude/stoic-khayyam-09b644`; der ist erledigt.
|
||||
|
||||
## AUSGANGSLAGE — nicht nochmal machen
|
||||
|
||||
- `bf-public` ist **healthy mit 12 Connectoren** (ap1/ap2/ap3, je ein `cloudflared 2026.6.1`,
|
||||
@@ -98,6 +106,8 @@ zuletzt. Nach **jedem** Namen die Abnahme aus §5.3, erst dann der nächste.
|
||||
|
||||
1. **Rotation zweier Nautobot-Tokens** (`NAUTOBOT_SUPERUSER_API_TOKEN`, `NAUTOBOT_GITEA_TOKEN`) —
|
||||
in der Vorsession ins Transkript geraten, als verbrannt zu behandeln. Gehört zu **TP30**.
|
||||
✅ **Von Christoph am 2026-08-31 ausdrücklich vertagt** („kommt später dran") — nicht von selbst
|
||||
anfangen, aber auch nicht vergessen: bis zur Rotation ist der Nautobot-Superuser-Token kompromittiert.
|
||||
2. **`crs326-core` / `wifi-security` / `ft-over-ds`** — offene Transaktion `TP25-fund-e-ft-over-ds`
|
||||
einer laufenden TP25-Session. **Nicht anfassen, nicht grün machen**, Ablauf 2026-09-03.
|
||||
3. **`mcp/mikromcp/config/routers.yaml`** meldet `rosVersion: "7.24"` für alle fünf, live ist
|
||||
|
||||
76
docs/tp23-stufe6-bypass-sperre-runbook.md
Normal file
76
docs/tp23-stufe6-bypass-sperre-runbook.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# TP23 Stufe 6 — DNS-Bypass-Sperre (Runbook für eine SEPARATE, VOR-ORT-Session)
|
||||
|
||||
> 🔴🔴 **HARTES GATE: NUR VOR ORT ausführen. NICHT aus der Ferne, nicht während Christoph
|
||||
> abwesend ist.** (Notiert 2026-09-06: Christoph ist ~1 Woche nicht vor Ort → in diesem Fenster
|
||||
> **gar nicht anfangen**, auch nicht die log-only-Vorstufe scharf lassen.)
|
||||
>
|
||||
> Grund: Die Sperre macht das AGH-Paar `.36`/`.37` zum **harten DNS-SPOF**. Bis heute kann jeder
|
||||
> Client bei einem AGH-Ausfall auf einen externen Resolver ausweichen; **nach** der Sperre nicht
|
||||
> mehr — ein AGH-Ausfall = **hausweiter DNS-Ausfall** (betrifft die Familie), und ohne physischen
|
||||
> Zugriff gibt es keinen schnellen Rollback. Eine falsch platzierte Drop-Regel kann außerdem den
|
||||
> **Fernzugang selbst** (WG/cf-mesh) aussperren, mit dem man den Fehler zurücknehmen wollte.
|
||||
|
||||
## Ziel
|
||||
Clients dürfen plain **DNS (udp/tcp 53)** und **DoT (853)** nur noch zu den erlaubten Resolvern
|
||||
(`10.40.20.36`, `10.40.20.37`, Core `10.40.X.1`) schicken. Externe DNS-Server (Smart-TV mit
|
||||
`8.8.8.8` hartkodiert, App-eigene Resolver) werden geblockt → **kein Umgehen des Filters**.
|
||||
Das ist der letzte Baustein von TP23 und lebt in der **TP5-Firewall** (`forward`-Kette).
|
||||
|
||||
## Voraussetzungen
|
||||
**Erfüllt (Stand 2026-09-06):**
|
||||
- Self-Service-Oberfläche steht und ist getestet (HA-Dashboard `dns-ausnahmen`, Stufe 5) → ein
|
||||
geblockter Dienst kann **ohne Admin** temporär freigegeben werden. Das war die harte
|
||||
Reihenfolge-Regel („erst der Ersatz, dann die Sperre").
|
||||
- `dns-bypass-exempt`-Gruppe existiert auf dem Resolver-Paar (AGH-Client-Seite).
|
||||
|
||||
**Noch zu bauen (Teil dieser Session, VOR dem Drop):**
|
||||
- **Firewall-Exempt** ist noch NICHT da: eine Address-List `dns-bypass-exempt` (permanent) mit dem
|
||||
dev-MacBook (`10.40.10.183` **und** `10.40.10.82`, dual-homed) + Agent-Toolchain, plus eine
|
||||
`accept`-Regel **vor** dem Drop. Ohne die verliert der Entwicklungsrechner seinen Ausweg.
|
||||
- Ad-hoc-JIT: Address-List `jit-dns-bypass` mit `timeout` nach dem Muster `jit-admin`
|
||||
(`routeros/tp5-etappe4-input-mgmt.rsc`) — selbstverfallende Freigabe.
|
||||
|
||||
## Bekannte Grenze (offen benennen, nicht „lösen")
|
||||
Die Sperre greift auf **Port** (53/853). **DoH läuft über 443** und ist damit portgleich zu HTTPS —
|
||||
ein Gerät, das DoH gegen `8.8.8.8:443` fährt, umgeht die Sperre. Das per SNI/IP zu schließen ist
|
||||
ein eigenes, größeres Thema (nicht Teil von TP23). Für den Alltag (TVs/IoT mit Plain-DNS) reicht die
|
||||
Port-Sperre.
|
||||
|
||||
## Sichere Methodik — log-only zuerst, Drop zuletzt
|
||||
1. **Exempt + JIT bauen** (via Nautobot GC, `ip-firewall-filter` steht unter Drift-Kontrolle → **kein
|
||||
Direkt-Write**): `accept` für `dns-bypass-exempt`/`jit-dns-bypass` → 53/853, platziert **vor** der
|
||||
künftigen Drop-Regel. Erst hier abnehmen, dass die Exempts wirklich durchkommen.
|
||||
2. **Log-only-Vorstufe**: eine Regel `TP5-WOULD-DROP-DNS`, die LAN→extern auf `dst-port 53,853`
|
||||
(udp+tcp), **nicht** zu `.36/.37/Core`, **nur loggt** (in den Kollektor `10.40.20.18:514`, wie die
|
||||
bestehende `TP5-WOULD-DROP`). **Mehrere Tage laufen lassen** und den Drop-Log lesen: *welche*
|
||||
Geräte reden mit *welchen* externen Resolvern? Jedes davon ist ein Kandidat, der nach dem Drop
|
||||
bricht — vorab entscheiden (Reservierung auf AGH, Exempt, oder bewusst brechen lassen).
|
||||
🔑 Merkregel aus dem E5-Drop-Log: Geräte fallen oft mit **udp/161/andere** nebenbei auf — nur die
|
||||
53/853-Zeilen zählen hier.
|
||||
3. **Erst nach ruhigem/verstandenem Log**: die Log-only-Regel auf `action=drop` (oder `reject` mit
|
||||
`icmp-port-unreachable`, damit Clients schneller auf den nächsten Resolver fallen) heben —
|
||||
**mit Auto-Revert-Absicherung** (Scheduler/Netwatch, der die Regel nach X Minuten deaktiviert,
|
||||
falls nicht bestätigt), analog zum TP5-E3/E4-Vorgehen. **Vor Ort**, mit offener Konsole.
|
||||
|
||||
## Was NICHT gesperrt werden darf (sonst Selbst-Aussperrung)
|
||||
- `.36`/`.37` → CF-DoH-Upstream (443) und Core-Resolver-Egress: die Resolver müssen raus.
|
||||
- Core `10.40.X.1` DoH-Egress.
|
||||
- **cf-mesh / WG-Pfad** (Fernzugang) — die Drop-Regel matcht nur `dst-port 53,853`; trotzdem vor dem
|
||||
Scharfschalten gegenprüfen, dass Management-Input (`cf-mesh`, HA `8728`, Nautobot `22`) unberührt
|
||||
bleibt.
|
||||
|
||||
## Rollback
|
||||
- GC-Deploy der vorherigen Version (Regel zurück auf `disabled`/entfernt) — bzw. der Auto-Revert.
|
||||
- Fällt das AGH-Paar bei aktiver Sperre aus: Drop-Regel deaktivieren (Vor-Ort-Konsole) → Clients
|
||||
können sofort wieder externe Resolver nutzen.
|
||||
|
||||
## Abnahme
|
||||
- Exempt-Host (dev-MacBook) löst extern weiter auf; ein Test-Gerät mit hartkodiertem `8.8.8.8` löst
|
||||
**nicht** mehr (aber über AGH schon).
|
||||
- Self-Service: eine geblockte Domain per HA-Button freigeben → wirkt; nach Ablauf wieder gefiltert.
|
||||
- Compliance nach dem GC-Deploy grün (`python3 nautobot/gc-transaktion.py status`, GC 140/140).
|
||||
|
||||
## Verweise
|
||||
- Stufe 4/5 (fertig): `adguard/README.md`, `adguard/ha-self-service.md`, `adguard/agh-exception.py`.
|
||||
- JIT-/Firewall-Muster: `routeros/tp5-etappe4-input-mgmt.rsc`; GC-Pipeline: `nautobot/gc-configplan.py`.
|
||||
- Kontext/Reihenfolge-Regel: TP23-Abschnitt in `docs/teilprojekte.md`.
|
||||
@@ -22,6 +22,7 @@ Damit wird aus "irgendwo zwischen 15:07 und 15:09 war es schlecht" ein Satz mit
|
||||
"""
|
||||
import argparse
|
||||
import csv
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@@ -98,24 +99,45 @@ def lade_pings_alt(pfad):
|
||||
return treffer
|
||||
|
||||
|
||||
def geraete(run_dir):
|
||||
"""Liste von Geraeten: (rolle, ping-Liste, funk-Liste).
|
||||
def _sampler_funk(pfad):
|
||||
"""funk-Liste (sekunde, iface, signal, phy_rate_oder_None) aus einer sampler-CSV."""
|
||||
funk = []
|
||||
if os.path.exists(pfad):
|
||||
for r in csv.DictReader(open(pfad)):
|
||||
if r.get("sta_signal"):
|
||||
funk.append((sec(r["ts_local"]), r.get("sta_iface") or "",
|
||||
int(r["sta_signal"]),
|
||||
int(r["sta_tx_rate"]) if (r.get("sta_tx_rate") or "").isdigit() else None))
|
||||
return funk
|
||||
|
||||
funk-Liste = (sekunde, iface, signal, phy_rate_oder_None). Die PHY-Rate gibt es nur
|
||||
fuer die Sonde (sampler.csv, 1-s-Takt); fuer die Referenz liefert beide-telefone.csv
|
||||
nur AP und Signal im 2-s-Takt. Das ist bewusst so und wird unten beim Ruhezustand
|
||||
beruecksichtigt -- ohne Rate ist der Befund schwaecher und wird auch so benannt.
|
||||
|
||||
def geraete(run_dir):
|
||||
"""Liste benannter Geraete: (name, ping-Liste, funk-Liste).
|
||||
|
||||
funk-Liste = (sekunde, iface, signal, phy_rate_oder_None).
|
||||
|
||||
Seit 2026-09-04 (N-Geraete-Umbau) schreibt die Harness pro Geraet walk-ping-<name>.csv
|
||||
UND sampler-<name>.csv -- jedes Paar wird als EIN benanntes Geraet gelesen, beliebig viele,
|
||||
ohne feste Sonde/Referenz-Rollen. Faellt auf das alte 2-Rollen-Schema zurueck (sampler.csv /
|
||||
walk-ping.csv / walk-ping-iphone.csv / beide-telefone.csv), damit Laeufe vor dem Umbau
|
||||
weiter auswertbar bleiben. Unterschieden wird an der NACKTEN sampler.csv/walk-ping.csv:
|
||||
die schreibt nur das alte Schema -- die neue Harness nie (immer mit -<name>). Ohne diese
|
||||
Klammer wuerde der glob unten die walk-ping-iphone.csv eines Alt-Laufs fassen und dessen
|
||||
Sonde (walk-ping.csv, ohne Suffix) stillschweigend verlieren.
|
||||
"""
|
||||
pfad = lambda n: os.path.join(run_dir, n)
|
||||
|
||||
sonde_funk = []
|
||||
if os.path.exists(pfad("sampler.csv")):
|
||||
for r in csv.DictReader(open(pfad("sampler.csv"))):
|
||||
if r.get("sta_signal"):
|
||||
sonde_funk.append((sec(r["ts_local"]), r.get("sta_iface") or "",
|
||||
int(r["sta_signal"]),
|
||||
int(r["sta_tx_rate"]) if (r.get("sta_tx_rate") or "").isdigit() else None))
|
||||
legacy = os.path.exists(pfad("sampler.csv")) or os.path.exists(pfad("walk-ping.csv"))
|
||||
if not legacy:
|
||||
gs = []
|
||||
for pp in sorted(glob.glob(os.path.join(run_dir, "walk-ping-*.csv"))):
|
||||
name = os.path.basename(pp)[len("walk-ping-"):-len(".csv")]
|
||||
gs.append((name, lade_pings(pp), _sampler_funk(pfad("sampler-%s.csv" % name))))
|
||||
if gs:
|
||||
return gs
|
||||
|
||||
# --- Legacy: 2-Rollen-Schema (Laeufe vor 2026-09-04) ---
|
||||
sonde_funk = _sampler_funk(pfad("sampler.csv"))
|
||||
ref_funk = []
|
||||
if os.path.exists(pfad("beide-telefone.csv")):
|
||||
for r in csv.DictReader(open(pfad("beide-telefone.csv"))):
|
||||
@@ -189,6 +211,9 @@ def main():
|
||||
gs = geraete(a.dir)
|
||||
if not any(g[1] or g[2] for g in gs):
|
||||
raise SystemExit("Weder Ping-Antworten noch Funkproben gefunden.")
|
||||
# Alte 2-Rollen-Laeufe tragen die Namen "Referenz"/"Sonde" und bekommen den Rollen-Text;
|
||||
# neue N-Geraete-Laeufe tragen Geraetenamen (iphone/s22/ipad/...) -- ohne Rollen-Erklaerung.
|
||||
legacy_rollen = any("Sonde" in r or "Referenz" in r for r, _, _ in gs)
|
||||
|
||||
rooms = []
|
||||
for m in csv.DictReader(open(os.path.join(a.dir, "markers.csv"))):
|
||||
@@ -209,9 +234,12 @@ def main():
|
||||
for i, r in enumerate(rooms)]
|
||||
|
||||
mehrere = len(gs) > 1
|
||||
if mehrere:
|
||||
if mehrere and legacy_rollen:
|
||||
print("REFERENZ = iPhone, roamt frei (was du hier wirklich hast)")
|
||||
print("SONDE = S22, auf den Gegen-AP gezwungen (was die Rückfallebene noch kann)\n")
|
||||
elif mehrere:
|
||||
print("Ein Block je Raum, eine Zeile je Gerät (%s) — alle frei roamend.\n"
|
||||
% ", ".join(r for r, _, _ in gs))
|
||||
print("%-15s %-17s %5s %-22s %-17s %s"
|
||||
% ("Raum", "Rolle", "Dauer", "Signal min/⌀/max", "Verlust", "längste Lücke"))
|
||||
print("-" * 100)
|
||||
@@ -262,9 +290,13 @@ def main():
|
||||
print("\nLesehilfe: eine längste Lücke über ~2 s ist für einen Videocall eine hörbare")
|
||||
print("Unterbrechung, über 10 s ist der Call praktisch tot. Signal unter −70 dBm ist die")
|
||||
print("Zone, in der das passiert.")
|
||||
if mehrere:
|
||||
if mehrere and legacy_rollen:
|
||||
print("\nDie interessante Spalte ist der Unterschied: gute Referenz + schlechte Sonde")
|
||||
print("= hier hängt alles an EINEM AP. Beide schlecht = echtes Loch ohne Rückfallebene.")
|
||||
elif mehrere:
|
||||
print("\nDie interessante Spalte ist der Unterschied ZWISCHEN den Geräten am selben Ort:")
|
||||
print("streuen Signal/Verlust stark, liegt es am Gerät (Antenne/Standby), nicht am Funk;")
|
||||
print("sind alle an einem Ort schlecht, ist es ein echtes Loch der Ausleuchtung.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
105
docs/tp25-pin-multi.sh
Executable file
105
docs/tp25-pin-multi.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# TP25 — MEHRERE Clients gleichzeitig band-genau auf je EINEN AP pinnen.
|
||||
#
|
||||
# Wozu (2026-09-04): die Gehweg-Messung soll pro AP getrennt zeigen, wie weit er reicht. Dazu
|
||||
# wird je Sonde GENAU EIN cap-wifiN erlaubt (also ein AP UND ein Band) und alle anderen per
|
||||
# access-list abgewiesen. Das iPhone bleibt bewusst UNGEPINNT (frei roamende Referenz).
|
||||
#
|
||||
# Unterschied zu tp25-pin-s22.sh: das pinnt EIN Geraet AP-genau (beide Baender). Hier: N
|
||||
# Geraete, band-genau, je eigener Tag TP25-PINM-<name> -- damit `off` sauber nur diese entfernt.
|
||||
#
|
||||
# set: TP25_PINSPEC="ipad|CA:..|ap1|5;macbook|56:..|ap2|5;s22|2A:..|ap3|5" bash tp25-pin-multi.sh set
|
||||
# verify: bash tp25-pin-multi.sh verify # zeigt je Sonde das aktuelle Interface
|
||||
# off: bash tp25-pin-multi.sh off # alle TP25-PINM-* weg
|
||||
#
|
||||
# Band im Spec: "5" = 5 GHz, "24"/"2"/"2.4" = 2,4 GHz. AP: ap1|ap2|ap3 (wie in der Live-Karte).
|
||||
#
|
||||
# 🔴 Die cap-wifiN-Zuordnung wird bei JEDEM Aufruf frisch aus der Karte (tp25-pin-s22.sh map)
|
||||
# gelesen -- sie wandert bei jedem CAP-Rejoin. Niemals cachen.
|
||||
# 🔴 access-list steht unter KEINER ComplianceRule -> kein Nautobot-Drift. Jede Regel traegt
|
||||
# ihren Tag; `off` raeumt vollstaendig auf.
|
||||
# 🔴 Bewusst KEINE assoziativen Arrays (declare -A): macOS /bin/bash ist 3.2. Lookup per grep.
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
TAG_PREFIX="TP25-PINM"
|
||||
ROUTER_IP="${TP25_MANAGER_IP:-10.40.99.1}"
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
ZIEL="${1:-verify}"
|
||||
|
||||
PW="$(grep -m1 '^CRS326_CORE_PASS=' ~/.secrets/credentials.env | cut -d= -f2- | sed 's/^["'"'"']//; s/["'"'"']$//')"
|
||||
[[ -n "$PW" ]] || { echo "CRS326_CORE_PASS nicht in ~/.secrets/credentials.env gefunden" >&2; exit 1; }
|
||||
|
||||
# 🔴 sshpass -e statt -p: PW nie in die Kommandozeile (ps/Trace-Leak, 2026-08-22). Ausgabe zusaetzlich maskiert.
|
||||
ros() {
|
||||
SSHPASS="$PW" sshpass -e ssh -o StrictHostKeyChecking=no -o ConnectTimeout=8 \
|
||||
"admin@${ROUTER_IP}" "$1" 2>&1 | sed "s/${PW//\//\\/}/***/g"
|
||||
}
|
||||
|
||||
# Live-Karte (cap-wifiN=apX/Band, je Zeile) als String. Reuse von tp25-pin-s22.sh (map).
|
||||
MAP=""
|
||||
declare -a ALL_IFACES
|
||||
lade_karte() {
|
||||
MAP="$(bash "$HERE/tp25-pin-s22.sh" map)"
|
||||
[[ -n "${MAP//[[:space:]]/}" ]] || { echo "Live-Karte leer -- haengen die CAPs am Manager?" >&2; exit 1; }
|
||||
ALL_IFACES=()
|
||||
while IFS='=' read -r iface _label; do [[ -n "$iface" ]] && ALL_IFACES+=("$iface"); done <<< "$MAP"
|
||||
}
|
||||
|
||||
label_of() { grep -m1 "^$1=" <<< "$MAP" | cut -d= -f2-; }
|
||||
|
||||
# ap + band -> cap-wifiN (aus der Karte). Band-Eingabe normalisieren.
|
||||
ziel_iface() { # $1=ap $2=band
|
||||
local want
|
||||
case "$2" in
|
||||
5|5g|5G|5GHz) want="$1/5GHz" ;;
|
||||
24|2|2.4|2,4|2g|2G) want="$1/2,4GHz" ;;
|
||||
*) echo "" ; return ;;
|
||||
esac
|
||||
grep -m1 "=${want}\$" <<< "$MAP" | cut -d= -f1
|
||||
}
|
||||
|
||||
kick() { ros "/interface wifi registration-table remove [find where mac-address=\"$1\"]" >/dev/null; }
|
||||
aufraeumen_alle() { ros "/interface wifi access-list remove [find where comment~\"$TAG_PREFIX\"]" >/dev/null; }
|
||||
|
||||
case "$ZIEL" in
|
||||
set)
|
||||
[[ -n "${TP25_PINSPEC:-}" ]] || { echo "TP25_PINSPEC fehlt (name|mac|ap|band;...)" >&2; exit 2; }
|
||||
lade_karte
|
||||
aufraeumen_alle
|
||||
IFS=';' read -ra ENTRIES <<< "$TP25_PINSPEC"
|
||||
for e in "${ENTRIES[@]}"; do
|
||||
[[ -z "${e//[[:space:]]/}" ]] && continue
|
||||
IFS='|' read -r name mac ap band <<< "$e"
|
||||
[[ -n "$name" && -n "$mac" && -n "$ap" && -n "$band" ]] || { echo "Spec-Eintrag unvollstaendig: '$e'" >&2; exit 2; }
|
||||
ziel="$(ziel_iface "$ap" "$band")"
|
||||
[[ -n "$ziel" ]] || { echo "Kein Interface fuer $ap/$band in der Karte -- AP am Manager? Abbruch." >&2; exit 1; }
|
||||
tag="${TAG_PREFIX}-${name}"
|
||||
# Alle Interfaces AUSSER dem Ziel abweisen -> nur $ziel bleibt erlaubt (AP + Band erzwungen).
|
||||
gesperrt=""
|
||||
for i in "${ALL_IFACES[@]}"; do
|
||||
[[ "$i" == "$ziel" ]] && continue
|
||||
ros "/interface wifi access-list add mac-address=$mac interface=$i action=reject comment=\"$tag\"" >/dev/null
|
||||
gesperrt="$gesperrt $i"
|
||||
done
|
||||
echo "$name ($mac) -> $ziel ($(label_of "$ziel")); abgewiesen:$gesperrt"
|
||||
kick "$mac"
|
||||
done
|
||||
echo; echo "Gesetzt. Kontrolle in ~6 s: bash $0 verify" ;;
|
||||
off)
|
||||
aufraeumen_alle; echo "Alle ${TAG_PREFIX}-* entfernt." ;;
|
||||
verify)
|
||||
lade_karte
|
||||
echo "--- aktive ${TAG_PREFIX}-Regeln ---"
|
||||
r="$(ros "/interface wifi access-list print terse where comment~\"$TAG_PREFIX\"")"
|
||||
[[ -z "${r//[[:space:]]/}" ]] && echo " (keine)" || echo "$r" | tr -d '\r' | sed 's/^/ /'
|
||||
echo "--- aktuelle Anmeldungen (Ziel-Kontrolle) ---"
|
||||
a="$(ros '/interface wifi registration-table print terse proplist=mac-address,interface,signal,ssid')"
|
||||
echo "$a" | tr -d '\r' | grep -E 'mac-address=' | while IFS= read -r line; do
|
||||
ifc="$(sed -n 's/.*interface=\([^ ]*\).*/\1/p' <<< "$line")"
|
||||
echo " ${line} [$(label_of "$ifc")]"
|
||||
done ;;
|
||||
map) bash "$HERE/tp25-pin-s22.sh" map ;;
|
||||
*) echo "Aufruf: $0 {set|verify|off|map} (set liest TP25_PINSPEC)" >&2; exit 2 ;;
|
||||
esac
|
||||
@@ -56,8 +56,14 @@ ros() {
|
||||
}
|
||||
|
||||
# cap-wifiN -> "apX Band" -- live, ohne Cache. Ausgabe je Zeile: cap-wifi3=ap1/5GHz
|
||||
# 🔴 channel.frequency ist seit dem DFS-Kanalplan (2026-09-03, Frequenz-Listen 5260,5280 /
|
||||
# 5300,5320) fuer die 5G-Radios ein ARRAY, kein Skalar. Die alte Zeile verglich das Array
|
||||
# direkt mit 3000 und lieferte fuer die betroffenen Radios Muell -- den `grep '^cap-wifi'`
|
||||
# samt pipefail dann verschluckte, sodass `map` LEER zurueckkam und ap-map.txt leer blieb.
|
||||
# Fix: bei :typeof=array das erste Element nehmen. Beleg-Kommando dieses Fundes am Manager:
|
||||
# `:foreach ... :put (name . " freq=" . channel.frequency)` -> "5260;5280" fuer cap-wifi1.
|
||||
karte() {
|
||||
ros ':foreach i in=[/interface wifi find where !master-interface] do={:local c [/interface wifi get $i cap]; :local f [/interface wifi get $i channel.frequency]; :local b "2,4GHz"; :if ($f > 3000) do={:set b "5GHz"}; :put ([/interface wifi get $i name] . "=" . [:pick $c 0 [:find $c "@"]] . "/" . $b)}' \
|
||||
ros ':foreach i in=[/interface wifi find where !master-interface] do={:local c [/interface wifi get $i cap]; :local fl [/interface wifi get $i channel.frequency]; :local f 0; :if ([:typeof $fl]="array") do={:set f [:tonum [:pick $fl 0]]} else={:set f [:tonum $fl]}; :local b "2,4GHz"; :if ($f > 3000) do={:set b "5GHz"}; :put ([/interface wifi get $i name] . "=" . [:pick $c 0 [:find $c "@"]] . "/" . $b)}' \
|
||||
| tr -d '\r' | grep '^cap-wifi[0-9]*='
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ cd "$HERE"
|
||||
|
||||
NAME="${1:-$(date +%Y%m%d-%H%M)}"
|
||||
export TP6_RUN_DIR="$HERE/docs/messdaten/tp25-runde-$NAME"
|
||||
export TP25_PHONE_IP="${TP25_PHONE_IP:-10.40.10.178}" # S22 -- wird gepingt
|
||||
export TP25_PHONE_MAC="${TP25_PHONE_MAC:-2A:0D:B0:5D:AD:A7}"
|
||||
export TP25_IPHONE_MAC="${TP25_IPHONE_MAC:-F2:62:4C:E1:AF:09}"
|
||||
# N-Geraete-Liste (name|ip|mac;...). Default = die bisherigen zwei, damit alte Aufrufe
|
||||
# unveraendert weiterlaufen. Wird an tp25-walk-messung.sh durchgereicht.
|
||||
export TP25_PHONES="${TP25_PHONES:-iphone|10.40.10.196|F2:62:4C:E1:AF:09;s22|10.40.10.178|2A:0D:B0:5D:AD:A7}"
|
||||
|
||||
mkdir -p "$TP6_RUN_DIR"
|
||||
|
||||
@@ -36,14 +36,6 @@ else
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
# 🔴 Gegen-AP-Automatik gleich einschalten. Sie war bisher ein Klick auf der Konsole -- und
|
||||
# wer ihn vergisst, geht die ganze Runde mit beiden Telefonen auf DEMSELBEN AP und merkt
|
||||
# es erst bei der Auswertung (im Test am 2026-08-22 genau so passiert). Abschalten geht
|
||||
# weiter jederzeit ueber den Knopf.
|
||||
curl -s -X POST --max-time 10 "http://127.0.0.1:3031/auto?an=1" >/dev/null 2>&1 \
|
||||
&& echo "Gegen-AP-Automatik: EIN" \
|
||||
|| echo "⚠️ Automatik konnte nicht eingeschaltet werden -- auf der Konsole nachholen!"
|
||||
|
||||
echo
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo " Konsole am Telefon oeffnen:"
|
||||
@@ -53,8 +45,8 @@ ifconfig | awk '/^[a-z0-9]+:/{i=substr($1,1,length($1)-1)}
|
||||
/inet /{if ($2 !~ /^127\.|^169\.254\./) printf " http://%s:3031/ (%s)\n", $2, i}'
|
||||
echo
|
||||
echo " 1) Auf dem Telefon einmal irgendwo tippen -> schaltet den Signalton frei"
|
||||
echo " 2) Gegen-AP-Automatik laeuft bereits -> S22 folgt dem iPhone spiegelverkehrt"
|
||||
echo " 3) Losgehen. Doppelton = beide angemeldet -> Raum antippen, weiter"
|
||||
echo " 2) In der Konsole pinnen (Multi-Pin) -> je Client AP/Band waehlen, 'Pin setzen'"
|
||||
echo " 3) Losgehen. Raum antippen, weiter -> Alarm = gepinnter Client haengt nirgends"
|
||||
echo
|
||||
echo " Lauf: $TP6_RUN_DIR"
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
@@ -63,18 +55,17 @@ echo
|
||||
aufraeumen() {
|
||||
echo
|
||||
echo "Runde beendet. Aufraeumen …"
|
||||
# 🔴 REIHENFOLGE: erst die Konsole toeten, dann den Pin loesen. Andersherum ist es ein
|
||||
# Wettlauf, den man verliert -- die Automatik der noch laufenden Konsole sieht den
|
||||
# geloesten Pin und setzt ihn binnen zwei Sekunden wieder. Am 2026-08-22 meldete der
|
||||
# Aufraeumer brav "AP-Pin geloest", und danach standen die Regeln trotzdem am Core:
|
||||
# das Telefon waere nach jeder Runde gepinnt geblieben.
|
||||
# 🔴 REIHENFOLGE: erst die Konsole toeten, dann den Pin loesen. Die Konsole pinnt nicht
|
||||
# mehr automatisch (die alte Gegen-AP-Automatik ist mit dem Multi-Pin-Umbau 2026-09-04
|
||||
# entfallen), aber sie haelt ggf. noch SSH-Sitzungen zum Manager offen -- die erst
|
||||
# beenden, bevor der Pin geloest wird.
|
||||
[[ -n "$KONSOLE" ]] && kill "$KONSOLE" 2>/dev/null && echo " Konsole beendet."
|
||||
# Muster bewusst ohne -e/-p: es gab beide Varianten, und die enge Fassung liess den
|
||||
# Sampler stehen.
|
||||
pkill -f 'sshpass.*10.40.99.1' 2>/dev/null
|
||||
pkill -f 'tp6-monitor-core.sh' 2>/dev/null
|
||||
sleep 1
|
||||
bash docs/tp25-pin-s22.sh off >/dev/null 2>&1 && echo " AP-Pin geloest."
|
||||
bash docs/tp25-pin-multi.sh off >/dev/null 2>&1 && echo " Multi-Pin geloest."
|
||||
echo
|
||||
echo "Auswertung:"
|
||||
echo " python3 docs/tp25-gehweg-auswertung.py --dir $TP6_RUN_DIR"
|
||||
|
||||
@@ -19,14 +19,24 @@
|
||||
set -uo pipefail
|
||||
|
||||
RUN_DIR="${TP6_RUN_DIR:-/private/tmp/claude-501/-Users-christophemsenhuber-dev-bf-network-r6/0d86ebd1-035f-4513-a231-5cca8111ecfd/scratchpad/tp6-run2}"
|
||||
PHONE="${TP25_PHONE_IP:-10.40.10.178}" # S22 -- wird gepingt und gesampelt
|
||||
PHONE_MAC="${TP25_PHONE_MAC:-2A:0D:B0:5D:AD:A7}"
|
||||
# 🔴 Seit dem Lauf vom 2026-08-22 wird das ZWEITE Telefon mitgepingt. Vorher lief der Ping
|
||||
# nur auf das gepinnte Geraet -- und weil das per Automatik immer auf dem GEGEN-AP sitzt,
|
||||
# fehlte ausgerechnet die Strecke, die die Alltagsabdeckung zeigt. Der Terrassen-Vergleich
|
||||
# liess sich deshalb nicht fuehren, obwohl beide Telefone dabei waren.
|
||||
PHONE2="${TP25_PHONE2_IP:-10.40.10.196}" # iPhone -- roamt frei
|
||||
PHONE2_NAME="${TP25_PHONE2_NAME:-iphone}"
|
||||
|
||||
# 🔴 Handy-Liste generalisiert (2026-09-03, TP25-4-Handy-Messung): statt zwei hartkodierter
|
||||
# Telefone eine Liste. Format: "name|ip|mac;name|ip|mac;..." -- '|' als Feldtrenner (die MAC
|
||||
# enthaelt selbst ':'), ';' als Listentrenner. Pro Handy laeuft EIN eigener Sampler
|
||||
# (sampler-<name>.csv) UND ein eigener Core-Ping (walk-ping-<name>.csv). Default = die
|
||||
# bisherigen zwei, damit alte Aufrufe unveraendert weiterlaufen.
|
||||
# Der Core-Ping (5/s) erzeugt zugleich den Dauer-Downlink, der die Taschen-Handys wach haelt.
|
||||
TP25_PHONES="${TP25_PHONES:-iphone|10.40.10.196|F2:62:4C:E1:AF:09;s22|10.40.10.178|2A:0D:B0:5D:AD:A7}"
|
||||
declare -a PH_NAME PH_IP PH_MAC
|
||||
IFS=';' read -ra _ENTRIES <<< "$TP25_PHONES"
|
||||
for _e in "${_ENTRIES[@]}"; do
|
||||
[[ -z "${_e//[[:space:]]/}" ]] && continue
|
||||
IFS='|' read -r _n _ip _mac <<< "$_e"
|
||||
[[ -n "$_n" && -n "$_ip" && -n "$_mac" ]] || { echo "TP25_PHONES-Eintrag unvollstaendig: '$_e' (erwartet name|ip|mac)" >&2; exit 2; }
|
||||
PH_NAME+=("$_n"); PH_IP+=("$_ip"); PH_MAC+=("$_mac")
|
||||
done
|
||||
[[ ${#PH_NAME[@]} -gt 0 ]] || { echo "TP25_PHONES leer/ungueltig: '$TP25_PHONES'" >&2; exit 2; }
|
||||
|
||||
STATE="$RUN_DIR/phase.json"
|
||||
MARKERS="$RUN_DIR/markers.csv"
|
||||
HERE="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
@@ -34,6 +44,14 @@ HERE="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
mkdir -p "$RUN_DIR"
|
||||
[[ -f "$MARKERS" ]] || echo "ts_epoch,ts_local,marker" > "$MARKERS"
|
||||
|
||||
# Client-Liste fuer die Klick-Konsole (docs/tp6-marker/server.py). Die Konsole liest sie
|
||||
# ueber den .current-run-Zeiger -- so kennt sie die N Geraete auch, wenn sie als
|
||||
# Dauer-Preview schon vor dem Messlauf lief. Format: name|ip|mac je Zeile.
|
||||
: > "$RUN_DIR/geraete.txt"
|
||||
for i in "${!PH_NAME[@]}"; do
|
||||
printf '%s|%s|%s\n' "${PH_NAME[$i]}" "${PH_IP[$i]}" "${PH_MAC[$i]}" >> "$RUN_DIR/geraete.txt"
|
||||
done
|
||||
|
||||
# Zeiger fuer die Klick-Konsole (docs/tp6-marker/server.py). Die laeuft als Dauer-Preview
|
||||
# auf Port 3031 und kennt dieses Verzeichnis sonst nicht -- ihre Marker landeten dann im
|
||||
# Lauf von gestern, waehrend der Sampler hierher schreibt. Beides fiel erst bei der
|
||||
@@ -51,10 +69,17 @@ bash "$HERE/docs/tp25-pin-s22.sh" map > "$RUN_DIR/ap-map.txt" 2>/dev/null \
|
||||
|| echo "⚠️ AP-Zuordnung konnte nicht gelesen werden -- Auswertung bleibt bei cap-wifiN"
|
||||
|
||||
# Frueheren Lauf beiseitelegen, statt ihn zu ueberschreiben.
|
||||
if [[ -f "$RUN_DIR/sampler.csv" ]]; then
|
||||
# 🔴 Seit dem N-Geraete-Umbau (2026-09-04) schreiben neue Laeufe pro Geraet
|
||||
# sampler-<name>.csv / walk-ping-<name>.csv -- der alte Trigger auf die nackte sampler.csv
|
||||
# haette einen Re-Run nicht mehr erkannt und den Vorlauf ueberschrieben. Legacy-Namen
|
||||
# (sampler.csv/walk-ping.csv/beide-telefone.csv aus 2-Rollen-Laeufen) bleiben in der Liste.
|
||||
if compgen -G "$RUN_DIR/sampler-*.csv" >/dev/null || compgen -G "$RUN_DIR/walk-ping-*.csv" >/dev/null \
|
||||
|| [[ -f "$RUN_DIR/sampler.csv" ]]; then
|
||||
ARCHIV="$RUN_DIR/archiv-$(date +%H%M%S)"; mkdir -p "$ARCHIV"
|
||||
for f in sampler.csv markers.csv walk-ping.csv walk-ping.log ping-dauerlauf.log; do
|
||||
[[ -f "$RUN_DIR/$f" ]] && mv "$RUN_DIR/$f" "$ARCHIV/"
|
||||
for f in "$RUN_DIR"/sampler.csv "$RUN_DIR"/sampler-*.csv "$RUN_DIR"/sampler-*.out \
|
||||
"$RUN_DIR"/markers.csv "$RUN_DIR"/walk-ping.csv "$RUN_DIR"/walk-ping-*.csv \
|
||||
"$RUN_DIR"/walk-ping.log "$RUN_DIR"/ping-dauerlauf.log "$RUN_DIR"/beide-telefone.csv; do
|
||||
[[ -f "$f" ]] && mv "$f" "$ARCHIV/"
|
||||
done
|
||||
echo "ts_epoch,ts_local,marker" > "$MARKERS"
|
||||
echo "Vorheriger Lauf -> $ARCHIV"
|
||||
@@ -74,9 +99,16 @@ PY
|
||||
|
||||
state "Kein Call nötig. <b>🚶</b> drücken, wenn du losgehst, <b>📍</b> wenn du stehen bleibst — und bitte den Weg gehen, den du beim Telefonieren wirklich gehst.<br><br>Ich pinge dein Telefon fünfmal pro Sekunde. Jeder AP- oder Bandwechsel zeigt sich dann als echter Paketverlust: <b>so lange ist der Call wirklich tot.</b><br><br>Am Ende: <b>⏹ Aufzeichnung stoppen</b>."
|
||||
|
||||
# Sampler am Manager (1-s-Takt, feiner als bei der TP6-Messung)
|
||||
bash "$HERE/docs/tp6-monitor-core.sh" --out "$RUN_DIR/sampler.csv" --mac "$PHONE_MAC" --interval 1 \
|
||||
> "$RUN_DIR/sampler.out" 2>&1 & SAMPLER=$!
|
||||
# Sampler am Manager -- pro Geraet einer. 2-s-Takt: bei 4 Geraeten laufen sonst 8 SSH-Sessions
|
||||
# gegen den Core-SPOF, und Signal alle 2 s reicht fuer einen Gehweg (der Ping bleibt fein bei
|
||||
# 200 ms). Jeder Sampler holt sich den Core-PW selbst (docs/tp6-monitor-core.sh, SSHPASS -e).
|
||||
declare -a SAMPLERS
|
||||
for i in "${!PH_NAME[@]}"; do
|
||||
bash "$HERE/docs/tp6-monitor-core.sh" --out "$RUN_DIR/sampler-${PH_NAME[$i]}.csv" \
|
||||
--mac "${PH_MAC[$i]}" --interval 2 \
|
||||
> "$RUN_DIR/sampler-${PH_NAME[$i]}.out" 2>&1 &
|
||||
SAMPLERS+=("$!")
|
||||
done
|
||||
|
||||
# 5 Pings/s auf JEDES Telefon — GEPINGT WIRD VOM CORE, nicht von diesem Rechner.
|
||||
# 🔴 Der Grund: pingt der Laptop, laeuft der Weg ueber ZWEI Funkstrecken (Laptop -> AP ->
|
||||
@@ -124,8 +156,11 @@ ping_lauf() {
|
||||
# stdout-Pipe schliesst, und der Hintergrundjob darin haelt sie offen -- das Skript blieb
|
||||
# dort stehen, der zweite Ping wurde nie gestartet (2026-08-22). Die Funktion laeuft in
|
||||
# der aktuellen Shell, also liefert $! danach die richtige PID.
|
||||
ping_lauf "$PHONE" "$RUN_DIR/walk-ping.csv"; PINGER=$!
|
||||
ping_lauf "$PHONE2" "$RUN_DIR/walk-ping-$PHONE2_NAME.csv"; PINGER2=$!
|
||||
declare -a PINGERS
|
||||
for i in "${!PH_NAME[@]}"; do
|
||||
ping_lauf "${PH_IP[$i]}" "$RUN_DIR/walk-ping-${PH_NAME[$i]}.csv"
|
||||
PINGERS+=("$!")
|
||||
done
|
||||
|
||||
# 🔴 Kinder ZUERST. `kill $SAMPLER` traf nur den Wrapper; dessen Subshell samt SSH-Sitzung
|
||||
# wurde dabei verwaist und lief weiter -- nach dem Stopp hielt der Core stumm eine
|
||||
@@ -138,9 +173,8 @@ killbaum() {
|
||||
}
|
||||
|
||||
beenden() {
|
||||
for pid in $SAMPLER $PINGER $PINGER2; do killbaum "$pid"; done
|
||||
pkill -f "ping $PHONE interval=200ms" 2>/dev/null
|
||||
pkill -f "ping $PHONE2 interval=200ms" 2>/dev/null
|
||||
for pid in "${SAMPLERS[@]}" "${PINGERS[@]}"; do killbaum "$pid"; done
|
||||
for ip in "${PH_IP[@]}"; do pkill -f "ping $ip interval=200ms" 2>/dev/null; done
|
||||
# Der /ping am Router endet mit der SSH-Sitzung (am 2026-08-22 nachgeprueft: nach dem
|
||||
# Kill der Sitzungen lief am Core nichts weiter). Bewusst KEIN "job remove" am Geraet --
|
||||
# ein pauschales Aufraeumen fremder Jobs waere ein zu grobes Werkzeug fuer ein Messskript.
|
||||
@@ -150,10 +184,12 @@ beenden() {
|
||||
}
|
||||
trap beenden EXIT
|
||||
|
||||
echo "Gehweg-Messung laeuft."
|
||||
echo " Funk -> $RUN_DIR/sampler.csv"
|
||||
echo " Ping -> $RUN_DIR/walk-ping.csv ($PHONE, gepinnt)"
|
||||
echo " Ping -> $RUN_DIR/walk-ping-$PHONE2_NAME.csv ($PHONE2, frei roamend)"
|
||||
echo "Gehweg-Messung laeuft (${#PH_NAME[@]} Geraete, alle frei roamend)."
|
||||
for i in "${!PH_NAME[@]}"; do
|
||||
printf ' %-9s Funk -> sampler-%s.csv Ping -> walk-ping-%s.csv (%s)\n' \
|
||||
"${PH_NAME[$i]}" "${PH_NAME[$i]}" "${PH_NAME[$i]}" "${PH_IP[$i]}"
|
||||
done
|
||||
echo " Verzeichnis: $RUN_DIR"
|
||||
echo " Stoppen: '⏹ Aufzeichnung stoppen' auf der Konsole -- oder Ctrl-C hier."
|
||||
|
||||
# 🔴 Bis 2026-08-22 lief hier nur `while true; do touch; sleep 5; done`, und das Skript war
|
||||
|
||||
38
docs/tp41-t5-idp-callback-anleitung.md
Normal file
38
docs/tp41-t5-idp-callback-anleitung.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# TP41 T5 — IdP-Callback-URLs reparieren (der Daily-OTP-Fix)
|
||||
|
||||
**Problem:** Nach dem Team-Domain-Rename `bf4` → `emsenhuber` kennen die OAuth-Apps bei GitHub/Google
|
||||
die neue Callback-URL nicht. Login schlägt mit „redirect_uri is not associated with this application"
|
||||
fehl → Cloudflare Access fällt auf **E-Mail-OTP** zurück (das tägliche Nervthema).
|
||||
|
||||
**Die EINE URL**, die bei beiden Providern hinterlegt sein muss:
|
||||
`https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback`
|
||||
|
||||
## GitHub (Client ID `Ov23li2h96hAkGRPJXYV`)
|
||||
1. github.com → rechts oben aufs Profilbild → **Settings**.
|
||||
2. Linke Spalte ganz unten **Developer settings** → **OAuth Apps**.
|
||||
3. Die App mit Client ID `Ov23li2h96hAkGRPJXYV` öffnen.
|
||||
4. **Authorization callback URL** = `https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback`.
|
||||
5. (Optional **Homepage URL** = `https://emsenhuber.cloudflareaccess.com`.)
|
||||
6. **Update application** klicken.
|
||||
|
||||
## Google (Client ID `276709275903-b3q55lsj203v4strbhh5mub76cib867e.apps.googleusercontent.com`)
|
||||
1. console.cloud.google.com → oben das richtige **Projekt** wählen.
|
||||
2. **APIs & Services** → **Credentials**.
|
||||
3. Unter **OAuth 2.0 Client IDs** den Client `276709275903-…apps.googleusercontent.com`
|
||||
(Typ *Web application*) öffnen.
|
||||
4. **Authorized redirect URIs** → **+ ADD URI** →
|
||||
`https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback`.
|
||||
5. **Authorized JavaScript origins** → **+ ADD URI** → `https://emsenhuber.cloudflareaccess.com`.
|
||||
6. **SAVE**. (Google-Propagation dauert teils ein paar Minuten.)
|
||||
|
||||
## Testen
|
||||
1. Neues **privates** Browserfenster → eine Access-geschützte Seite öffnen.
|
||||
2. Beim CF-Login **GitHub** bzw. **Google** wählen → muss ohne „redirect_uri"-Fehler durchlaufen,
|
||||
**keine** OTP-Mail mehr.
|
||||
3. Gegenprobe (optional, kann Claude read-only): CF-Audit
|
||||
`GET /accounts/<acc>/access/logs/access_requests` → `identity_provider` = `github`/`google`
|
||||
statt `onetimepin`.
|
||||
|
||||
## Hinweis
|
||||
Die Team-Domain heißt `emsenhuber.cloudflareaccess.com` (das alte Org-Label `bf4…` in CF nicht
|
||||
anfassen). Session gilt 720 h (30 Tage) — nach dem Fix sollte der Login also lange halten.
|
||||
@@ -16,12 +16,12 @@ Zwei Aufgaben:
|
||||
- Die Seite hat ein <meta refresh>. Ohne JS aktualisiert sich die Anleitung dadurch
|
||||
trotzdem; laeuft JS, entfernt es das Meta-Tag und pollt stattdessen leise.
|
||||
|
||||
🔴 SEIT 2026-08-22 AENDERT DIESE SEITE DOCH ETWAS AM NETZ: der AP-Pin (TP25) schreibt
|
||||
🔴 SEIT 2026-08-22 AENDERT DIESE SEITE DOCH ETWAS AM NETZ: der Multi-Pin (TP25) schreibt
|
||||
access-list-Regeln auf den WLAN-Manager. Die Seite bindet auf 0.0.0.0 und kennt keine
|
||||
Authentifizierung — wer in VLAN10 steht, kann den Pin umschalten. Das ist fuer die Dauer
|
||||
einer Messung vertretbar und sonst nicht: den Server nach dem Rundgang beenden. Der Pin
|
||||
selbst ist harmlos genug (er betrifft eine MAC), aber die Regel ist es nicht, die als
|
||||
naechstes hier landen koennte.
|
||||
Authentifizierung — wer in VLAN10 steht, kann pinnen. Das ist fuer die Dauer einer Messung
|
||||
vertretbar und sonst nicht: den Server nach dem Rundgang beenden. Der Pin selbst ist
|
||||
harmlos genug (er betrifft MACs), aber die Regel ist es nicht, die als naechstes hier
|
||||
landen koennte.
|
||||
|
||||
Bindet auf 0.0.0.0 (Bedienung vom iPhone/iPad).
|
||||
"""
|
||||
@@ -164,6 +164,82 @@ def sampler_tail():
|
||||
return {}
|
||||
|
||||
|
||||
def geraete():
|
||||
"""Liste (name, ip, mac) aus geraete.txt im Laufverzeichnis.
|
||||
|
||||
🔴 Die Datei schreibt tp25-walk-messung.sh beim Start des Messlaufs (eine Zeile
|
||||
name|ip|mac je Client). Fehlt sie — Alt-Lauf oder Dauer-Preview, die schon vor dem
|
||||
ersten Lauf lief — fallen wir auf die zwei bisherigen Geraete zurueck, damit die
|
||||
Anzeige nicht leer ist. Die Namen muessen zu den sampler-<name>.csv /
|
||||
walk-ping-<name>.csv passen, die die Harness schreibt.
|
||||
"""
|
||||
try:
|
||||
zeilen = [z.strip() for z in open(_p("geraete.txt")) if z.strip()]
|
||||
gs = []
|
||||
for z in zeilen:
|
||||
teile = z.split("|")
|
||||
if len(teile) >= 3 and teile[0]:
|
||||
gs.append((teile[0], teile[1], teile[2]))
|
||||
if gs:
|
||||
return gs
|
||||
except Exception:
|
||||
pass
|
||||
return [("iphone", "", "F2:62:4C:E1:AF:09"), ("s22", "", "2A:0D:B0:5D:AD:A7")]
|
||||
|
||||
|
||||
def client_tail(name):
|
||||
"""Letzte Sampler-Zeile EINES Geraets (sampler-<name>.csv). Fehlt sie, ist das kein Fehler.
|
||||
|
||||
Gleiche Spalten wie sampler_tail() — die Harness schreibt pro Geraet einen eigenen
|
||||
Sampler mit demselben Header (tp6-monitor-core.sh). Die Konsole braucht deshalb KEINE
|
||||
eigene SSH-Sitzung mehr: sie liest nur, was die Sampler schon auf die Platte legen.
|
||||
"""
|
||||
try:
|
||||
pfad = _p("sampler-%s.csv" % name)
|
||||
rows = [r.strip() for r in open(pfad) if r.strip()]
|
||||
if len(rows) < 2:
|
||||
return {}
|
||||
row = dict(zip(rows[0].split(","), rows[-1].split(",")))
|
||||
return {
|
||||
"age": int(time.time() - int(row.get("ts_epoch", "0"))),
|
||||
"cpu": row.get("cpu", ""), "wan_rx": row.get("wan_rx_bps", ""),
|
||||
"wan_tx": row.get("wan_tx_bps", ""), "iface": row.get("sta_iface", ""),
|
||||
"signal": row.get("sta_signal", ""), "tx_rate": row.get("sta_tx_rate", ""),
|
||||
"sta_tx_bps": row.get("sta_tx_bps", ""), "sta_rx_bps": row.get("sta_rx_bps", ""),
|
||||
}
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def ping_loss(name, n=150):
|
||||
"""Ping-Verlust der letzten ~n Zeilen von walk-ping-<name>.csv (5 Pings/s -> n=150 ~ 30 s).
|
||||
|
||||
Leeres ms-Feld = Verlust. Liefert (verloren, gesamt) oder None, wenn noch keine Daten da
|
||||
sind. Der Header (ts_local,seq,ms) wird ueber die nicht-numerische seq-Spalte uebersprungen.
|
||||
"""
|
||||
try:
|
||||
rows = [r.strip() for r in open(_p("walk-ping-%s.csv" % name)) if r.strip()]
|
||||
verloren = gesamt = 0
|
||||
for z in rows[-n:]:
|
||||
teile = z.split(",")
|
||||
if len(teile) >= 3 and teile[1].isdigit():
|
||||
gesamt += 1
|
||||
if not teile[2].strip():
|
||||
verloren += 1
|
||||
return (verloren, gesamt) if gesamt else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def wan_tail():
|
||||
"""WAN/CPU-Anzeige: aus sampler.csv (Alt-Lauf) oder dem ersten Geraet-Sampler."""
|
||||
w = sampler_tail()
|
||||
if w.get("cpu") or w.get("wan_rx"):
|
||||
return w
|
||||
gs = geraete()
|
||||
return client_tail(gs[0][0]) if gs else {}
|
||||
|
||||
|
||||
def kill_flows():
|
||||
"""Not-Aus: Saettigungs-Flows sofort beenden."""
|
||||
killed = 0
|
||||
@@ -214,153 +290,104 @@ def ap_map():
|
||||
return _apmap["karte"]
|
||||
|
||||
|
||||
# 🔎 Die Messidee (Christoph, 2026-08-22): das iPhone roamt frei und zeigt damit, welchen AP
|
||||
# ein normaler Client an dieser Stelle waehlt -- das wissen wir also ohnehin. Interessant
|
||||
# ist der ANDERE. Deshalb wird das S22 automatisch auf den Gegen-AP gezwungen: pro Standort
|
||||
# gibt es dann zwei Messpunkte statt einem, ohne zweimal zu gehen.
|
||||
IPHONE_MAC = os.environ.get("TP25_IPHONE_MAC", "F2:62:4C:E1:AF:09")
|
||||
S22_MAC = os.environ.get("TP25_PIN_MAC", "2A:0D:B0:5D:AD:A7")
|
||||
# 🔎 Die Messidee (Christoph, 2026-08-22, generalisiert 2026-09-04): die Clients roamen frei
|
||||
# und zeigen damit, welchen AP ein normaler Client an dieser Stelle waehlt. Fuer die
|
||||
# Abdeckungsfrage wird je Client per access-list GENAU EIN AP+Band erlaubt
|
||||
# (tp25-pin-multi.sh). Die alte Gegen-AP-Automatik (S22 folgt dem iPhone) ist damit
|
||||
# ueberholt: gepinnt wird vorab band-genau, nicht mehr automatisch waehrend des Gehens.
|
||||
|
||||
# Was der Beobachter sieht. "" = nicht angemeldet.
|
||||
_live = {"iphone": "", "iphone_sig": "", "s22": "", "s22_sig": "", "stand": 0.0}
|
||||
_auto = {"an": False, "seit_weg": 0.0, "aufgegeben": ""}
|
||||
PINM_SH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "tp25-pin-multi.sh")
|
||||
|
||||
# Pin-Zustand. Das Setzen dauert ~8 s (Regeln + Kick), deshalb laeuft es in einem Thread und
|
||||
# die Seite zeigt solange "setze Pin …". pins = {name: "ap|band"} der zuletzt gesetzten Auswahl.
|
||||
_pinm = {"busy": False, "msg": "", "pins": {}, "stand": 0.0}
|
||||
|
||||
|
||||
def core_passwort():
|
||||
"""Aus dem Credential-Store. Wird nie geloggt und nie in die Seite gerendert."""
|
||||
with open(os.path.expanduser("~/.secrets/credentials.env")) as fh:
|
||||
for zeile in fh:
|
||||
if zeile.startswith("CRS326_CORE_PASS="):
|
||||
return zeile.split("=", 1)[1].strip().strip("\"'")
|
||||
raise RuntimeError("CRS326_CORE_PASS nicht gefunden")
|
||||
def pin_targets():
|
||||
"""Eindeutige (ap, band)-Paare aus der Live-Karte, band-normalisiert fuer tp25-pin-multi.sh.
|
||||
|
||||
|
||||
def _ap_von(iface):
|
||||
return ap_map().get(iface, "").split(" /")[0]
|
||||
|
||||
|
||||
def beobachter():
|
||||
"""Haelt EINE SSH-Sitzung offen und liest beide Telefone im 2-s-Takt.
|
||||
|
||||
🔴 Bewusst kein Poll mit je einem ssh-Aufruf: das waeren ueber einen Rundgang mehrere
|
||||
hundert Verbindungsaufbauten, jeder ~1 s. Dasselbe Muster wie tp6-monitor-core.sh --
|
||||
inklusive Reconnect-Schleife, weil die Sitzung am 2026-08-21 mitten in einer Messung
|
||||
weggebrochen ist und die Daten still endeten.
|
||||
ap_map() liefert 'apX / 5 GHz' bzw. 'apX / 2,4 GHz'; das Skript erwartet Band '5' oder '24'.
|
||||
"""
|
||||
# 🔴 KEINE Klammern um die :while-Schleife -- "(:while ...)" laesst RouterOS die
|
||||
# Sitzung wortlos beenden, und mit stderr auf DEVNULL sieht man nur, dass alle 3 s
|
||||
# ein neuer ssh startet. Genau so lag der Beobachter am 2026-08-22 tot.
|
||||
ros = (':while (true) do={'
|
||||
':local a [/interface/wifi/registration-table find where mac-address="%s"];'
|
||||
':local b [/interface/wifi/registration-table find where mac-address="%s"];'
|
||||
':local ai ""; :local as2 ""; :local bi ""; :local bs "";'
|
||||
':if ([:len $a] > 0) do={:set ai [/interface/wifi/registration-table get [:pick $a 0] interface];'
|
||||
':set as2 [/interface/wifi/registration-table get [:pick $a 0] signal]};'
|
||||
':if ([:len $b] > 0) do={:set bi [/interface/wifi/registration-table get [:pick $b 0] interface];'
|
||||
':set bs [/interface/wifi/registration-table get [:pick $b 0] signal]};'
|
||||
':put ($ai . "," . $as2 . "," . $bi . "," . $bs); :delay 2s;}'
|
||||
% (IPHONE_MAC, S22_MAC))
|
||||
while True:
|
||||
try:
|
||||
pw = core_passwort()
|
||||
# 🔴 sshpass -e statt -p: bei -p steht das Router-Passwort in der KOMMANDOZEILE
|
||||
# und damit in `ps`, in jedem Prozess-Trace und in jeder Debug-Ausgabe, die
|
||||
# argv anfasst. Am 2026-08-22 ist es genau so im Klartext in einem Trace
|
||||
# gelandet. Mit -e liegt es nur in der Umgebung dieses einen Kindprozesses.
|
||||
umgebung = dict(os.environ, SSHPASS=pw)
|
||||
proc = subprocess.Popen(
|
||||
["sshpass", "-e", "ssh", "-o", "StrictHostKeyChecking=no",
|
||||
"-o", "ConnectTimeout=8", "-o", "ServerAliveInterval=15",
|
||||
"admin@10.40.99.1", ros],
|
||||
stdout=subprocess.PIPE, stderr=open(_p("beobachter.log"), "a"),
|
||||
text=True, bufsize=1, env=umgebung)
|
||||
# 🔴 NICHT `for zeile in proc.stdout`: die Iteration eines Pipes liest blockweise
|
||||
# vor, die Zeilen kommen also erst an, wenn ~4 KB beisammen sind -- bei einer
|
||||
# Zeile alle 2 s waere das eine Stunde. readline() liefert sofort.
|
||||
for zeile in iter(proc.stdout.readline, ""):
|
||||
teile = zeile.strip().split(",")
|
||||
if len(teile) != 4:
|
||||
continue
|
||||
_live.update(iphone=teile[0], iphone_sig=teile[1],
|
||||
s22=teile[2], s22_sig=teile[3], stand=time.time())
|
||||
# 🔴 Bis 2026-08-22 blieben diese Zahlen NUR im Speicher, fuer die Anzeige.
|
||||
# Nach dem Rundgang fehlte deshalb die halbe Messung: das S22 sitzt per
|
||||
# Automatik immer auf dem Gegen-AP, die Alltagsabdeckung zeigt das iPhone
|
||||
# -- und genau dessen Zeitreihe war weg. Nachtraeglich liess sich nur das
|
||||
# Roaming-Log am Manager retten: Ereignisse, keine Kurve.
|
||||
mitschreiben(teile)
|
||||
entscheide()
|
||||
except Exception as e:
|
||||
# Ein Beobachter, der still stirbt, ist schlimmer als keiner (Lehre aus dem
|
||||
# Sampler-Abbruch am 2026-08-21). Also mitschreiben statt schlucken.
|
||||
try:
|
||||
with open(_p("beobachter.log"), "a") as fh:
|
||||
fh.write("%s %s: %s\n" % (time.strftime("%H:%M:%S"), type(e).__name__, e))
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(3)
|
||||
ziele, gesehen = [], set()
|
||||
for wert in ap_map().values():
|
||||
ap, _, band = wert.partition(" / ")
|
||||
band = band.replace(" GHz", "").replace(",", ".")
|
||||
if band.startswith("5"):
|
||||
band = "5"
|
||||
elif band.startswith("2"):
|
||||
band = "24"
|
||||
else:
|
||||
continue
|
||||
if (ap, band) not in gesehen:
|
||||
gesehen.add((ap, band))
|
||||
ziele.append((ap, band))
|
||||
return sorted(ziele)
|
||||
|
||||
|
||||
def mitschreiben(teile):
|
||||
"""Beide Telefone im 2-s-Takt in den Lauf schreiben: iface + Signal je Geraet."""
|
||||
try:
|
||||
pfad = _p("beide-telefone.csv")
|
||||
frisch = not os.path.exists(pfad) or os.path.getsize(pfad) == 0
|
||||
with open(pfad, "a") as fh:
|
||||
if frisch:
|
||||
fh.write("ts_epoch,ts_local,iphone_iface,iphone_sig,s22_iface,s22_sig\n")
|
||||
fh.write("%d,%s,%s\n" % (time.time(), time.strftime("%H:%M:%S"), ",".join(teile)))
|
||||
except Exception:
|
||||
pass
|
||||
def build_spec(form):
|
||||
"""Aus den Formular-Auswahlen (pin_<name>=ap|band oder frei) den TP25_PINSPEC-String bauen.
|
||||
|
||||
Clients ohne Ziel (frei) bleiben frei — tp25-pin-multi.sh set raeumt vorher alle
|
||||
TP25-PINM-*-Regeln ab und setzt nur die hier genannten.
|
||||
"""
|
||||
eintraege = []
|
||||
for name, _ip, mac in geraete():
|
||||
wert = (form.get("pin_%s" % name) or ["frei"])[0]
|
||||
if wert and wert != "frei" and "|" in wert:
|
||||
ap, band = wert.split("|", 1)
|
||||
eintraege.append("%s|%s|%s|%s" % (name, mac, ap, band))
|
||||
return ";".join(eintraege)
|
||||
|
||||
|
||||
def entscheide():
|
||||
"""Gegen-AP setzen, sobald das iPhone den AP wechselt."""
|
||||
if not _auto["an"] or _pin["busy"]:
|
||||
return
|
||||
ip_ap = _ap_von(_live["iphone"])
|
||||
if ip_ap not in ("ap1", "ap2"):
|
||||
return # iPhone selbst nicht angemeldet -> nichts zu spiegeln
|
||||
gegen = "ap1" if ip_ap == "ap2" else "ap2"
|
||||
if pin_lesen() != gegen:
|
||||
_auto["aufgegeben"] = ""
|
||||
_auto["seit_weg"] = time.time()
|
||||
pin_setzen(gegen)
|
||||
def pinm_aktion(spec):
|
||||
"""Pin setzen (spec = 'name|mac|ap|band;...') oder loesen (spec = ''). Laeuft im Thread."""
|
||||
pins = {}
|
||||
for e in (spec.split(";") if spec else []):
|
||||
teile = e.split("|")
|
||||
if len(teile) >= 4:
|
||||
pins[teile[0]] = "%s|%s" % (teile[2], teile[3])
|
||||
|
||||
|
||||
# Pin-Zustand. Das Umschalten dauert ~8 s (Regeln + Kick + Nachlesen), deshalb laeuft es
|
||||
# in einem Thread und die Seite zeigt solange "schaltet um".
|
||||
_pin = {"ziel": None, "busy": False, "msg": "", "stand": 0.0}
|
||||
|
||||
|
||||
def pin_lesen():
|
||||
if _pin["busy"] or time.time() - _pin["stand"] < 20:
|
||||
return _pin["ziel"]
|
||||
try:
|
||||
_pin["ziel"] = subprocess.run(["bash", PIN_SH, "which"], capture_output=True,
|
||||
text=True, timeout=20).stdout.strip() or None
|
||||
_pin["stand"] = time.time()
|
||||
except Exception:
|
||||
pass
|
||||
return _pin["ziel"]
|
||||
|
||||
|
||||
def pin_setzen(ziel):
|
||||
def lauf():
|
||||
try:
|
||||
r = subprocess.run(["bash", PIN_SH, ziel], capture_output=True, text=True, timeout=60)
|
||||
_pin["msg"] = (r.stdout.strip().splitlines() or [""])[0]
|
||||
umgebung = dict(os.environ)
|
||||
if spec:
|
||||
umgebung["TP25_PINSPEC"] = spec
|
||||
r = subprocess.run(["bash", PINM_SH, "set"], capture_output=True, text=True,
|
||||
timeout=90, env=umgebung)
|
||||
else:
|
||||
r = subprocess.run(["bash", PINM_SH, "off"], capture_output=True, text=True,
|
||||
timeout=90)
|
||||
_pinm["msg"] = r.stdout.strip() or r.stderr.strip() or "ok"
|
||||
except Exception as e:
|
||||
_pin["msg"] = "Fehler: %s" % e
|
||||
_pinm["msg"] = "Fehler: %s" % e
|
||||
finally:
|
||||
_pin["busy"] = False
|
||||
_pin["stand"] = 0.0
|
||||
pin_lesen()
|
||||
_pin["busy"] = True
|
||||
_pin["msg"] = "schaltet um …"
|
||||
_pinm["busy"] = False
|
||||
_pinm["stand"] = time.time()
|
||||
|
||||
_pinm["busy"] = True
|
||||
_pinm["msg"] = "setze Pin …" if spec else "löse Pin …"
|
||||
_pinm["pins"] = pins
|
||||
# Der Klick gehoert in dieselbe Zeitachse wie alles andere — sonst laesst sich hinterher
|
||||
# nicht sagen, welche Messpunkte zu welchem AP gehoeren.
|
||||
write_marker("PIN=%s" % ziel)
|
||||
# nicht sagen, welche Messpunkte zu welchem Pin gehoeren.
|
||||
write_marker("PINM=%s" % (spec or "off"))
|
||||
threading.Thread(target=lauf, daemon=True).start()
|
||||
|
||||
|
||||
def pinm_verify():
|
||||
"""tp25-pin-multi.sh verify im Thread — zeigt Regeln + aktuelle Anmeldungen."""
|
||||
def lauf():
|
||||
try:
|
||||
r = subprocess.run(["bash", PINM_SH, "verify"], capture_output=True, text=True,
|
||||
timeout=60)
|
||||
_pinm["msg"] = r.stdout.strip() or r.stderr.strip() or "ok"
|
||||
except Exception as e:
|
||||
_pinm["msg"] = "Fehler: %s" % e
|
||||
finally:
|
||||
_pinm["busy"] = False
|
||||
_pinm["stand"] = time.time()
|
||||
|
||||
_pinm["busy"] = True
|
||||
_pinm["msg"] = "prüfe …"
|
||||
threading.Thread(target=lauf, daemon=True).start()
|
||||
|
||||
|
||||
@@ -391,27 +418,42 @@ def fmt_bps(v):
|
||||
|
||||
|
||||
def render(st):
|
||||
w = sampler_tail()
|
||||
w = wan_tail()
|
||||
rest = max(0, int(st.get("ends", 0) - time.time())) if st.get("ends") else 0
|
||||
mode = st.get("mode", "wartet")
|
||||
|
||||
banner = ""
|
||||
alarm = False # nur DIESER Zustand loest Ton + Vibration aus, nicht jeder Banner
|
||||
# 🔴 Der wichtigste Alarm der Seite, seit es den AP-Pin gibt (2026-08-22): ein vom Pin
|
||||
# ABGEWIESENER Verbindungsversuch ist in den Ping-Daten nicht von einem Funkloch zu
|
||||
# unterscheiden -- und der Manager protokolliert die Abweisung auf info-Ebene nicht.
|
||||
# Android quittiert sie mit "Verbindung fehlgeschlagen" und WAEHLT DAS NETZ AB, danach
|
||||
# misst der restliche Rundgang nur noch Stille. Deshalb wird "haengt nirgends" hier
|
||||
# nicht klein in der WLAN-Zeile gezeigt, sondern schreit.
|
||||
if pin_lesen() in ("ap1", "ap2") and w.get("iface") == "absent" and w.get("age", 999) < 30:
|
||||
alarm = True
|
||||
banner = ('<div class="banner warn">📵 S22 HÄNGT NIRGENDS — Display an und wieder auf '
|
||||
'dirtyvader-main verbinden. Der Pin wirft es vom gesperrten AP; Android '
|
||||
'wählt das Netz dann von selbst ab. <b>Nicht weitergehen</b>, sonst misst '
|
||||
'du Stille statt Abdeckung.</div>')
|
||||
haengende = []
|
||||
|
||||
# 🔴 Der wichtigste Alarm der Seite, seit es den Pin gibt (2026-08-22, generalisiert
|
||||
# 2026-09-04): ein vom Pin ABGEWIESENER Verbindungsversuch ist in den Ping-Daten nicht
|
||||
# von einem Funkloch zu unterscheiden -- und der Manager protokolliert die Abweisung auf
|
||||
# info-Ebene nicht. Android quittiert sie mit "Verbindung fehlgeschlagen" und WAEHLT DAS
|
||||
# NETZ AB, danach misst der restliche Rundgang nur noch Stille. Deshalb wird "haengt
|
||||
# nirgends" hier nicht klein in der Client-Zeile gezeigt, sondern schreit.
|
||||
clients = []
|
||||
for name, ip, mac in geraete():
|
||||
t = client_tail(name)
|
||||
pl = ping_loss(name)
|
||||
iface = t.get("iface", "")
|
||||
ap = ap_map().get(iface, iface) if iface else ""
|
||||
signal = t.get("signal", "")
|
||||
frisch = t.get("age", 999) < 30
|
||||
gepinnt = name in _pinm["pins"]
|
||||
if gepinnt and iface == "absent" and frisch:
|
||||
alarm = True
|
||||
haengende.append(name)
|
||||
clients.append((name, ip, mac, iface, ap, signal, pl, frisch, gepinnt))
|
||||
|
||||
if haengende:
|
||||
banner = ('<div class="banner warn">📵 <b>%s</b> HÄNGT NIRGENDS — der Pin wirft das '
|
||||
'Geraet vom gesperrten AP; Android waehlt das Netz dann von selbst ab. '
|
||||
'<b>Nicht weitergehen</b>, sonst misst du Stille statt Abdeckung.</div>'
|
||||
% ", ".join(haengende))
|
||||
elif not st.get("driver"):
|
||||
banner = ('<div class="banner done">ℹ️ Keine Ping-Aufzeichnung — Räume markieren und '
|
||||
'AP-Pin gehen trotzdem. Für die Messkurve <b>tp25-walk-messung.sh</b> starten.</div>')
|
||||
'pinnen geht trotzdem. Für die Messkurve <b>tp25-walk-messung.sh</b> starten.</div>')
|
||||
elif mode == "langzeit":
|
||||
banner = ('<div class="banner done">✅ MESSUNG ABGESCHLOSSEN — die Zahlen liegen vor. '
|
||||
'Ab jetzt läuft nur noch die Langzeit-Aufzeichnung.</div>')
|
||||
@@ -423,86 +465,65 @@ def render(st):
|
||||
countdown = ('<div class="cd" id="cd" data-ends="%d">noch ~%d s</div>' % (st.get("ends", 0), rest)
|
||||
if rest else '<div class="cd" id="cd" data-ends="0"></div>')
|
||||
|
||||
wlan = "—"
|
||||
if w.get("iface"):
|
||||
wlan = "%s · %s dBm · tx %s / rx %s" % (
|
||||
ap_map().get(w["iface"], w["iface"]), w.get("signal", "?"),
|
||||
fmt_bps(w.get("sta_tx_bps")), fmt_bps(w.get("sta_rx_bps")))
|
||||
# Client-Karten: je Geraet Name, AP+Signal, Ping-Verlust der letzten ~30 s.
|
||||
karten = ""
|
||||
for name, ip, mac, iface, ap, signal, pl, frisch, gepinnt in clients:
|
||||
if iface and iface != "absent":
|
||||
status = ("%s · %s dBm" % (ap, signal)) if signal else ap
|
||||
elif iface == "absent":
|
||||
status = "<b>nirgends</b>"
|
||||
else:
|
||||
status = "—"
|
||||
if pl:
|
||||
verloren, gesamt = pl
|
||||
ping = "%d/%d verloren" % (verloren, gesamt)
|
||||
else:
|
||||
ping = "—"
|
||||
karten += ('<div class="card"><div class="phase">%s</div>'
|
||||
'<div class="inst"><b>%s</b></div>'
|
||||
'<div class="cval">%s</div>'
|
||||
'<div class="cval">Ping: %s</div></div>'
|
||||
% ("📌 gepinnt" if gepinnt else "Client", name, status, ping))
|
||||
|
||||
ziel = pin_lesen()
|
||||
ip_ap, s22_ap = _ap_von(_live["iphone"]), _ap_von(_live["s22"])
|
||||
frisch = time.time() - _live["stand"] < 15
|
||||
# Pin-UI: je Client ein Ziel-Dropdown, dazu setzen/loesen/verify.
|
||||
ziele = pin_targets()
|
||||
|
||||
# Drei Zustaende, nicht zwei. "S22 kommt nicht rein" ist ein ERGEBNIS (der Gegen-AP
|
||||
# traegt hier nicht), kein Defekt -- es darf deshalb nicht wie ein Fehler aussehen und
|
||||
# nicht ewig Alarm schlagen.
|
||||
# 🔴 "beide angemeldet" ist NICHT das Kriterium -- der Messpunkt taugt nur, wenn die
|
||||
# beiden Telefone auf VERSCHIEDENEN APs sitzen. Am 2026-08-22 meldete die Seite
|
||||
# "✅ beide angemeldet, auf verschiedenen APs", waehrend beide auf ap2 hingen: ein
|
||||
# gruenes Licht fuer eine Messung, die es gar nicht gab. Wieder derselbe Fehler --
|
||||
# die Anzeige geprueft statt der Wirkung.
|
||||
getrennt = bool(ip_ap and s22_ap and ip_ap != s22_ap)
|
||||
bereit = bool(frisch and getrennt)
|
||||
gleich = bool(frisch and ip_ap and s22_ap and ip_ap == s22_ap)
|
||||
wartet = bool(frisch and ip_ap and not s22_ap and not _auto["aufgegeben"])
|
||||
if wartet and _auto["seit_weg"] and time.time() - _auto["seit_weg"] > 45:
|
||||
_auto["aufgegeben"] = ziel or "?"
|
||||
write_marker("UNERREICHBAR=%s" % (ziel or "?"))
|
||||
wartet = False
|
||||
def optionen(aktuell):
|
||||
out = ['<option value="frei"%s>frei</option>' % (" selected" if aktuell == "frei" else "")]
|
||||
for ap, band in ziele:
|
||||
wert = "%s|%s" % (ap, band)
|
||||
label = "%s / %s GHz" % (ap, "5" if band == "5" else "2,4")
|
||||
out.append('<option value="%s"%s>%s</option>'
|
||||
% (wert, " selected" if wert == aktuell else "", label))
|
||||
return "".join(out)
|
||||
|
||||
def z(ap, sig, mac_name):
|
||||
if not frisch:
|
||||
return "%s: —" % mac_name
|
||||
return ("%s: <b>%s</b> %s dBm" % (mac_name, ap, sig)) if ap else ("%s: <b>nirgends</b>" % mac_name)
|
||||
zeilen = ""
|
||||
for name, ip, mac in geraete():
|
||||
zeilen += ('<div class="pinzeile"><label>%s</label>'
|
||||
'<select name="pin_%s">%s</select></div>'
|
||||
% (name, name, optionen(_pinm["pins"].get(name, "frei"))))
|
||||
|
||||
doppel = "%s · %s" % (z(ip_ap, _live["iphone_sig"], "iPhone"),
|
||||
z(s22_ap, _live["s22_sig"], "S22"))
|
||||
|
||||
if _pin["busy"]:
|
||||
pinstatus = "⏳ %s<br>%s" % (_pin["msg"], doppel)
|
||||
elif _auto["aufgegeben"]:
|
||||
pinstatus = ("🚫 S22 bekommt <b>%s</b> hier nicht — <b>das ist das Messergebnis</b>, "
|
||||
"Raum markieren und weitergehen.<br>%s" % (_auto["aufgegeben"], doppel))
|
||||
elif bereit:
|
||||
pinstatus = "✅ beide angemeldet, <b>verschiedene APs</b> — Messpunkt zählt<br>%s" % doppel
|
||||
elif gleich and _auto["an"]:
|
||||
pinstatus = ("⏳ beide auf <b>%s</b> — Gegen-AP wird gerade nachgezogen, "
|
||||
"noch nicht weitergehen<br>%s" % (ip_ap, doppel))
|
||||
elif gleich:
|
||||
pinstatus = ("⚠️ beide auf <b>%s</b> — <b>kein Gegen-AP-Messpunkt.</b> "
|
||||
"Automatik einschalten oder S22 von Hand pinnen.<br>%s" % (ip_ap, doppel))
|
||||
elif wartet:
|
||||
pinstatus = "⏳ S22 sucht <b>%s</b> …<br>%s" % (ziel or "?", doppel)
|
||||
elif ziel in ("ap1", "ap2"):
|
||||
pinstatus = "S22 gepinnt auf <b>%s</b><br>%s" % (ziel, doppel)
|
||||
elif ziel == "off":
|
||||
pinstatus = "kein Pin — S22 roamt frei<br>%s" % doppel
|
||||
if _pinm["busy"]:
|
||||
pinstatus = "⏳ %s" % _pinm["msg"].replace("\n", "<br>")
|
||||
elif _pinm["msg"]:
|
||||
pinstatus = _pinm["msg"].replace("\n", "<br>")
|
||||
elif not ziele:
|
||||
pinstatus = "Manager nicht erreichbar — keine Pin-Ziele."
|
||||
else:
|
||||
pinstatus = "Zustand unbekannt (Manager nicht erreichbar?)"
|
||||
pinkarte = (
|
||||
'<div class="card"><span id="sig" data-alarm="%d" data-busy="%d" data-pin="%s" '
|
||||
'data-bereit="%d"></span>'
|
||||
'<div class="phase">AP-Pin S22</div>'
|
||||
'<div class="inst" id="pininst">%s</div><div class="raster">'
|
||||
'<form method="post" action="/pin?ap=ap1" onsubmit="return sendpin(event,\'ap1\')">'
|
||||
'<button class="raum%s" type="submit">ap1</button></form>'
|
||||
'<form method="post" action="/pin?ap=ap2" onsubmit="return sendpin(event,\'ap2\')">'
|
||||
'<button class="raum%s" type="submit">ap2</button></form>'
|
||||
'</div>'
|
||||
'<form method="post" action="/auto" onsubmit="return sendauto(event)">'
|
||||
'<button class="%s" style="margin-top:8px" type="submit">%s</button></form>'
|
||||
'<form method="post" action="/pin?ap=off" onsubmit="return sendpin(event,\'off\')">'
|
||||
'<button class="cam" style="margin-top:8px" type="submit">Pin lösen</button></form>'
|
||||
'</div>' % (1 if alarm else 0, 1 if _pin["busy"] else 0, ziel or "?",
|
||||
1 if bereit else 0,
|
||||
pinstatus,
|
||||
" hier" if ziel == "ap1" else "",
|
||||
" hier" if ziel == "ap2" else "",
|
||||
"ok" if _auto["an"] else "cam",
|
||||
"🔁 Gegen-AP: AN (folgt dem iPhone)" if _auto["an"]
|
||||
else "🔁 Gegen-AP automatisch",
|
||||
)
|
||||
)
|
||||
pinstatus = "Je Client AP/Band wählen, dann „Pin setzen“."
|
||||
|
||||
pinm_karte = (
|
||||
'<div class="card"><span id="sig" data-alarm="%d" data-busy="%d"></span>'
|
||||
'<div class="phase">Pinnen (Multi-Pin)</div>'
|
||||
'<div class="inst" id="pininst">%s</div>'
|
||||
'<form method="post" action="/pinmulti" onsubmit="return sendpinm(event)">'
|
||||
'%s'
|
||||
'<button class="ok" type="submit">📌 Pin setzen</button></form>'
|
||||
'<form method="post" action="/pinmulti?off=1" onsubmit="return sendpinmoff(event)">'
|
||||
'<button class="cam" type="submit">Pin lösen</button></form>'
|
||||
'<form method="post" action="/pinmulti?verify=1" onsubmit="return sendpinmoff(event)">'
|
||||
'<button class="cam" type="submit">verify</button></form>'
|
||||
'</div>' % (1 if alarm else 0, 1 if _pinm["busy"] else 0, pinstatus, zeilen))
|
||||
|
||||
raum, seit = current_room()
|
||||
# 🔴 Die Kacheln hingen bis 2026-08-22 am Treiber-Zustand -- ohne laufenden TP6-Treiber
|
||||
@@ -547,8 +568,9 @@ def render(st):
|
||||
return PAGE.format(
|
||||
banner=banner, title=st.get("title", "—"), phase=st.get("phase", "—"),
|
||||
instruction=st.get("instruction", ""), prog=prog, countdown=countdown,
|
||||
raumzeile=raumzeile, pinkarte=pinkarte, wlan=wlan, wan="rx %s / tx %s · CPU %s%%" % (fmt_bps(w.get("wan_rx")),
|
||||
fmt_bps(w.get("wan_tx")), w.get("cpu", "?")),
|
||||
raumzeile=raumzeile, clients=karten, pinm_karte=pinm_karte,
|
||||
wan="rx %s / tx %s · CPU %s%%" % (fmt_bps(w.get("wan_rx")),
|
||||
fmt_bps(w.get("wan_tx")), w.get("cpu", "?")),
|
||||
last=last_marker(), buttons=btns, notaus=notaus,
|
||||
)
|
||||
|
||||
@@ -579,6 +601,11 @@ button:active{{filter:brightness(1.3)}}
|
||||
.raster form{{margin:0}}
|
||||
.raum{{margin:0;padding:16px 8px;font-size:16px;background:#1e3a5f}}
|
||||
.raum.hier{{background:#0ea5e9;color:#06202e;box-shadow:0 0 0 3px #7dd3fc inset}}
|
||||
.cval{{font:14px/1.6 ui-monospace,Menlo,monospace;color:#9aa4b2;margin-top:2px}}
|
||||
.pinzeile{{display:flex;align-items:center;gap:10px;margin:8px 0}}
|
||||
.pinzeile label{{flex:0 0 90px;font-weight:600}}
|
||||
.pinzeile select{{flex:1;padding:10px;font-size:16px;background:#262b34;color:#e8eaed;
|
||||
border:1px solid #2a2f3a;border-radius:8px}}
|
||||
form{{margin:0}}
|
||||
</style>
|
||||
{banner}
|
||||
@@ -589,10 +616,10 @@ form{{margin:0}}
|
||||
{countdown}
|
||||
{prog}
|
||||
</div>
|
||||
{pinkarte}
|
||||
{clients}
|
||||
{pinm_karte}
|
||||
{raumzeile}
|
||||
<div class="live">WLAN {wlan}
|
||||
WAN {wan}
|
||||
<div class="live">WAN {wan}
|
||||
Marker {last}</div>
|
||||
{buttons}
|
||||
{notaus}
|
||||
@@ -638,18 +665,10 @@ function alarmton(){{ ton(880,180,0); ton(660,180,0.24); ton(880,260,0.48);
|
||||
function okton(){{ ton(1320,90,0); ton(1760,120,0.11);
|
||||
try{{ navigator.vibrate && navigator.vibrate(90); }}catch(e){{}} }}
|
||||
|
||||
function bereitton(){{ ton(1180,110,0); ton(1580,150,0.13);
|
||||
try{{ navigator.vibrate && navigator.vibrate([60,60,60]); }}catch(e){{}} }}
|
||||
|
||||
var letzterAlarm = 0, letzterBusy = 0, letzterBereit = 0, alarmTimer = null;
|
||||
var letzterAlarm = 0, letzterBusy = 0, alarmTimer = null;
|
||||
function signale(){{
|
||||
var sig = document.getElementById('sig'); if(!sig) return;
|
||||
var alarm = sig.dataset.alarm === '1', busy = sig.dataset.busy === '1';
|
||||
var bereit = sig.dataset.bereit === '1';
|
||||
// Der Piep, auf den Christoph wartet: beide Telefone haengen, auf verschiedenen APs --
|
||||
// der Messpunkt ist vollstaendig, weitergehen. Nur bei ZUSTANDSWECHSEL, nicht dauernd.
|
||||
if(bereit && !letzterBereit) bereitton();
|
||||
letzterBereit = bereit ? 1 : 0;
|
||||
if(alarm && !letzterAlarm){{
|
||||
alarmton();
|
||||
// Solange nichts geschieht, alle 12 s erinnern -- ein einmaliger Piep in der Hosentasche
|
||||
@@ -657,7 +676,7 @@ function signale(){{
|
||||
if(!alarmTimer) alarmTimer = setInterval(alarmton, 12000);
|
||||
}}
|
||||
if(!alarm && alarmTimer){{ clearInterval(alarmTimer); alarmTimer = null; }}
|
||||
if(!busy && letzterBusy) okton(); // Umschalten fertig
|
||||
if(!busy && letzterBusy) okton(); // Pin-Aktion fertig
|
||||
letzterAlarm = alarm ? 1 : 0; letzterBusy = busy ? 1 : 0;
|
||||
}}
|
||||
|
||||
@@ -672,28 +691,22 @@ function sendstop(ev){{
|
||||
return false;
|
||||
}}catch(e){{ return true; }}
|
||||
}}
|
||||
function sendauto(ev){{
|
||||
function sendpinm(ev){{
|
||||
try{{
|
||||
ev.preventDefault(); unlock(); okton();
|
||||
fetch('/auto', {{method:'POST'}}).catch(function(){{}});
|
||||
setTimeout(refresh, 400); setTimeout(refresh, 3000);
|
||||
var inst = document.getElementById('pininst');
|
||||
if(inst) inst.innerHTML = '⏳ setze Pin …<br>Gepinnte Geräte fliegen kurz aus dem WLAN und verbinden sich neu.';
|
||||
var fd = new FormData(ev.target);
|
||||
fetch('/pinmulti', {{method:'POST', body: new URLSearchParams(fd)}}).catch(function(){{}});
|
||||
setTimeout(refresh, 3000); setTimeout(refresh, 9000); setTimeout(refresh, 20000);
|
||||
return false;
|
||||
}}catch(e){{ return true; }}
|
||||
}}
|
||||
function sendpin(ev, ap){{
|
||||
function sendpinmoff(ev){{
|
||||
try{{
|
||||
ev.preventDefault(); unlock();
|
||||
// 🔴 Der Klick kommt vom S22 SELBST -- also von genau dem Geraet, das der Pin gleich vom
|
||||
// WLAN wirft. Die Antwort auf dieses fetch() kommt deshalb womoeglich nie an, und die
|
||||
// Seite kann sich nicht mehr nachladen. Die Anweisung muss JETZT auf dem Schirm
|
||||
// stehen, solange die Verbindung noch steht.
|
||||
var inst = document.getElementById('pininst');
|
||||
if(inst) inst.innerHTML = '⏳ schalte auf <b>' + ap + '</b> …<br>' +
|
||||
'<b>Dieses Telefon fliegt jetzt aus dem WLAN.</b> Wenn die Seite haengt: in den ' +
|
||||
'WLAN-Einstellungen wieder auf <b>dirtyvader-main</b> verbinden, dann laedt sie von selbst.';
|
||||
okton();
|
||||
fetch('/pin?ap=' + encodeURIComponent(ap), {{method:'POST'}}).catch(function(){{}});
|
||||
setTimeout(refresh, 3000); setTimeout(refresh, 9000); setTimeout(refresh, 20000);
|
||||
ev.preventDefault(); unlock(); okton();
|
||||
fetch(ev.target.action, {{method:'POST'}}).catch(function(){{}});
|
||||
setTimeout(refresh, 3000); setTimeout(refresh, 9000);
|
||||
return false;
|
||||
}}catch(e){{ return true; }}
|
||||
}}
|
||||
@@ -767,37 +780,27 @@ class Handler(BaseHTTPRequestHandler):
|
||||
self._send(200, json.dumps({"ok": True})) if "text/html" not in (
|
||||
self.headers.get("Accept") or "") else self._back()
|
||||
return
|
||||
if self.path.startswith("/auto"):
|
||||
# Ohne Parameter umschalten (das macht der Knopf), mit ?an=0|1 gezielt setzen --
|
||||
# tp25-runde.sh schaltet damit beim Start scharf. Ein Toggle waere dort falsch:
|
||||
# laeuft die Konsole schon mit Automatik, haette der Start sie AUSgeschaltet.
|
||||
if "an=" in self.path:
|
||||
_auto["an"] = self.path.split("an=", 1)[1].split("&")[0] in ("1", "true", "an")
|
||||
if self.path.startswith("/pinmulti"):
|
||||
if _pinm["busy"]:
|
||||
if "text/html" in (self.headers.get("Accept") or ""):
|
||||
self._back()
|
||||
else:
|
||||
self._send(409, json.dumps({"error": "laeuft schon"}))
|
||||
return
|
||||
qs = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
|
||||
if qs.get("off"):
|
||||
pinm_aktion("")
|
||||
elif qs.get("verify"):
|
||||
pinm_verify()
|
||||
else:
|
||||
_auto["an"] = not _auto["an"]
|
||||
_auto["aufgegeben"] = ""
|
||||
_auto["seit_weg"] = time.time()
|
||||
write_marker("AUTO=%s" % ("an" if _auto["an"] else "aus"))
|
||||
if _auto["an"]:
|
||||
entscheide()
|
||||
laenge = int(self.headers.get("Content-Length") or 0)
|
||||
body = self.rfile.read(laenge).decode("utf-8") if laenge else ""
|
||||
form = urllib.parse.parse_qs(body)
|
||||
pinm_aktion(build_spec(form))
|
||||
if "text/html" in (self.headers.get("Accept") or ""):
|
||||
self._back()
|
||||
else:
|
||||
self._send(200, json.dumps({"ok": True, "auto": _auto["an"]}))
|
||||
return
|
||||
if self.path.startswith("/pin?"):
|
||||
ap = urllib.parse.unquote(self.path.split("ap=", 1)[1].split("&")[0])
|
||||
if ap not in ("ap1", "ap2", "off"):
|
||||
self._send(400, json.dumps({"error": "ap muss ap1, ap2 oder off sein"}))
|
||||
return
|
||||
if _pin["busy"]:
|
||||
self._send(409, json.dumps({"error": "laeuft schon"}))
|
||||
return
|
||||
pin_setzen(ap)
|
||||
if "text/html" in (self.headers.get("Accept") or ""):
|
||||
self._back()
|
||||
else:
|
||||
self._send(200, json.dumps({"ok": True, "ziel": ap}))
|
||||
self._send(200, json.dumps({"ok": True}))
|
||||
return
|
||||
if self.path.startswith("/m?"):
|
||||
# 🔴 Erst dekodieren, dann NICHT hochschreiben: "RAUM%3DDiele%20OG" wurde sonst zu
|
||||
@@ -836,8 +839,7 @@ if __name__ == "__main__":
|
||||
print("Marker -> %s" % markers_pfad())
|
||||
for iface, wo in sorted(ap_map().items()):
|
||||
print(" %-14s %s" % (iface, wo))
|
||||
threading.Thread(target=beobachter, daemon=True).start()
|
||||
# 🔴 Threading ist Pflicht, seit der Pin dazugekommen ist: das Umschalten redet ueber SSH
|
||||
# 🔴 Threading ist Pflicht, seit der Pin dazugekommen ist: das Setzen redet ueber SSH
|
||||
# mit dem Manager und braucht ~8 s. Mit dem alten HTTPServer (single-threaded) haette
|
||||
# das die ganze Konsole blockiert -- inklusive Not-Aus.
|
||||
ThreadingHTTPServer(("0.0.0.0", PORT), Handler).serve_forever()
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/interface bridge vlan set [find where vlan-ids=10 and !dynamic] tagged=ether1,ether3,ether8,ether13,ether15
|
||||
/interface bridge vlan set [find where vlan-ids=20 and !dynamic] tagged=ether3,ether8,ether13,ether15
|
||||
/interface bridge vlan set [find where vlan-ids=30 and !dynamic] tagged=ether1,ether3,ether8,ether15
|
||||
/interface bridge vlan set [find where vlan-ids=40 and !dynamic] tagged=ether1,ether3,ether8,ether13,ether15 untagged=ether2,ether4,ether5
|
||||
/interface bridge vlan set [find where vlan-ids=50 and !dynamic] tagged=ether1,ether3,ether8,ether15
|
||||
/interface bridge vlan set [find where vlan-ids=90 and !dynamic] tagged=ether1,ether3,ether8,ether15
|
||||
/interface bridge vlan set [find where vlan-ids=99 and !dynamic] tagged=ether3,ether8,ether15,bridge
|
||||
15
docs/transaktionen/TEST-ether3-trunk-ap1-sideboard-2.json
Normal file
15
docs/transaktionen/TEST-ether3-trunk-ap1-sideboard-2.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"change_id": "TEST-ether3-trunk-ap1-sideboard-2",
|
||||
"device": "crs326-core",
|
||||
"scope": "bridge-vlan",
|
||||
"match_config": [
|
||||
"/interface bridge vlan"
|
||||
],
|
||||
"reason": "ap1 testweise am Sideboard, Uplink auf ether3 (Messung TP25)",
|
||||
"started": "2026-09-03",
|
||||
"expires": "2026-09-10",
|
||||
"state": "committed",
|
||||
"snapshot": "docs/transaktionen/TEST-ether3-trunk-ap1-sideboard-2.snapshot.rsc",
|
||||
"device_backup": "",
|
||||
"closed": "2026-09-03"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user