diff --git a/CLAUDE.md b/CLAUDE.md index 4897893..26cd1c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,8 @@ # BF-Netzwerk — Projekt-Kontext (auto-read) **Standort BF:** VLAN-segmentiertes Heimnetz auf MikroTik/RouterOS. Ziel: CAKE/QoS gegen Bufferbloat, -DNS/DHCP-Ablösung, WLAN via Standalone-APs (kein CAPsMAN), Firewall Least-Privilege, Multi-Site VPN. +DNS/DHCP-Ablösung, WLAN via **CAPsMAN auf dem Core** (TP28, 2026-08-17 — der Standalone-Entscheid von +2026-07-22 ist revidiert), Firewall Least-Privilege (**TP5 deny-by-default scharf seit 2026-08-18**), Multi-Site VPN. **Für jede TP-Session: zuerst `docs/teilprojekte.md` lesen** — enthält kanonischen Stand, Scope, Abhängigkeiten und Reihenfolge aller Teilprojekte. Kein anderer Kontext nötig. @@ -29,10 +30,10 @@ GW je VLAN = `.1` (crs326-core L3) · Mgmt VLAN99: core `.99.1`, branch `.99.2`, |---|---|---| | ~~ALLNET Core-Switch (sw1)~~ | — | ❌ **außer Betrieb (2026-08-08)** — durch `crs326-core` (L3-Router + Core-Switch, Technik UG) ersetzt; physisch abgelöst. (Telnet-Runner `switch/` = nur noch historisch.) | | ~~Omada Access-Switch (sw2)~~ | — | ❌ **abgebaut 2026-07-23** (TP15 Branch-Tausch) — durch `crs326-branch` in Technik OG ersetzt, physisch entfernt | -| **crs326-branch** (CRS326, Technik OG) | **10.40.99.2** (VLAN99; temp VLAN10 `.10.2`) · Bootstrap Rev4 2026-08-08 | RouterOS 7.19.5 · `admin`/`~/.secrets` (`CRS326_BRANCH_*`) · REST `http://10.40.99.2/rest` · MikroMCP `crs326-branch` ✅ **live** (2026-08-16 verifiziert) · **TP15 ✅: ersetzt sw2** (L2-Switch), volle Portbelegung (ether1 Uplink-Trunk, 2/8 NAS, 3 Drucker, 4 Dock, 5/6 Sonos, 7 macmini, 24 ap2) · sw-id RGZJ-UK0T, MAC 04:F4:1C:B4:15:58 | -| **crs326-core** (CRS326, Technik UG) | **10.40.99.1** (VLAN99-SVI = L3-GW; same-subnet-Fallback `10.40.10.1`) · Identity `crs326-core` | RouterOS 7.19.5 · `admin`/`~/.secrets` (`CRS326_CORE_*`) · MikroMCP routerId `crs326-core` ✅ **live** (2026-08-16 verifiziert) · **TP15/TP21.1 ✅ 2026-08-08: PRODUKTIVER L3-Router** (ersetzt ap1) — Routing/DHCP (7 Server + 54 Leases)/DNS (plain `1.1.1.1`, DoH-Cloudflare-TODO)/NAT/WG-Hub (fm+dw live); WAN `vlan100`=Liwest `90.146.33.177` · sw-id 4W04-URHT, MAC 04:F4:1C:B4:17:76 | -| hAP ax² #1 (ap1) | **10.40.99.11** (VLAN99) · Identity `ap1` | RouterOS 7.23.2 · `admin`/`~/.secrets` (`ROUTER_AP1_*`) · REST `http://10.40.99.11/rest` · MikroMCP `ap1` ✅ live · **TP3-Rebuild ✅ 2026-08-08: reiner Standalone-AP, KEIN CAPsMAN** — Uplink `ether1` (PoE-Port, `poe-out=off`) an crs326-core `ether15`; 6 SSIDs dirtyvader-main/-infra/-iot/-media/-untrusted/-guest, ch36/ch1; jede SSID mit `datapath` (TP3.1-Leck gefixt) · MAC D0:EA:11:4D:40:E0 · Config-Referenz `routeros/.secrets/ap1-prov-base.rsc` | -| hAP ax² #2 (ap2) | **10.40.99.12** (VLAN99) · Identity `ap2` | RouterOS 7.23.2 · `admin`/`~/.secrets` (`ROUTER_AP2_*`) · REST `http://10.40.99.12/rest` · MikroMCP `ap2` · **TP3-Rebuild ✅ 2026-08-08: reiner Standalone-AP** — Uplink `ether1` (PoE) an crs326-branch `ether24`; identisch zu ap1, ch149/ch11 · MAC D0:EA:11:4D:40:3A · Config `routeros/.secrets/ap2-prov-base.rsc` | +| **crs326-branch** (CRS326, Technik OG) | **10.40.99.2** (VLAN99) · Bootstrap Rev4 2026-08-08 | RouterOS **7.24** · `admin`/`~/.secrets` (`CRS326_BRANCH_*`) · REST `http://10.40.99.2/rest` · MikroMCP `crs326-branch` ✅ **live** (2026-08-16 verifiziert) · **TP15 ✅: ersetzt sw2** (L2-Switch), volle Portbelegung (ether1 Uplink-Trunk, 2/8 NAS, 3 Drucker, 4 Dock, 5/6 Sonos, 7 macmini, 24 ap2) · sw-id RGZJ-UK0T, MAC 04:F4:1C:B4:15:58 | +| **crs326-core** (CRS326, Technik UG) | **10.40.99.1** (VLAN99-SVI = L3-GW; same-subnet-Fallback `10.40.10.1`) · Identity `crs326-core` | RouterOS **7.24** · `admin`/`~/.secrets` (`CRS326_CORE_*`) · MikroMCP routerId `crs326-core` ✅ **live** (2026-08-16 verifiziert) · **TP15/TP21.1 ✅ 2026-08-08: PRODUKTIVER L3-Router** (ersetzt ap1) — Routing/DHCP (7 Server + 54 Leases)/DNS (**DoH zum CF-Gateway mit `verify-doh-cert=yes`**, TP23 Stufe 1 ✅ 2026-08-18; `servers=1.1.1.1` nur noch Bootstrap) · **NTP-Server für den Standort**/NAT/WG-Hub (fm+dw live); WAN `vlan100`=Liwest `90.146.33.177` · sw-id 4W04-URHT, MAC 04:F4:1C:B4:17:76 | +| hAP ax² #1 (ap1) | **10.40.99.11** (VLAN99) · Identity `ap1` | RouterOS **7.24** · `admin`/`~/.secrets` (`ROUTER_AP1_*`) · REST `http://10.40.99.11/rest` · MikroMCP `ap1` ✅ live · **TP28 ✅ 2026-08-17: reiner CAP** (Manager = `crs326-core`, `cap enabled=yes`, `discovery-interfaces=vlan99`) — Uplink `ether1` (PoE-Port, `poe-out=off`) an crs326-core `ether15`; SSIDs/Kanäle kommen vom Manager, ch36/ch1 · MAC D0:EA:11:4D:40:E0 · Config-Referenz `routeros/.secrets/ap1-prov-base.rsc` | +| hAP ax² #2 (ap2) | **10.40.99.12** (VLAN99) · Identity `ap2` | RouterOS **7.24** · `admin`/`~/.secrets` (`ROUTER_AP2_*`) · REST `http://10.40.99.12/rest` · MikroMCP `ap2` · **TP28 ✅ 2026-08-17: reiner CAP** — Uplink `ether1` (PoE) an crs326-branch `ether24`; ch44/ch11 (TP25: ch149 war unter ETSI leistungsbegrenzt) · MAC D0:EA:11:4D:40:3A · Config `routeros/.secrets/ap2-prov-base.rsc` | | **🔑 Einheitliches Admin-PW (2026-08-08)** | alle 4 MikroTik (core/branch/ap1/ap2) | user `admin`, gleiches PW (`~/.secrets/credentials.env` → `ROUTER_*_PASS`/`CRS326_*_PASS`; „Überlebensversicherung", User-Vorgabe). Werks-Defaults ap1/ap2 damit obsolet. | | NAS (nas-bf, DS923) | 10.40.20.10 | SSH `adm.christoph@10.40.20.10` (kein PW nötig) · Docker (Portainer endpointId=14) | | platform-pg (LXC 105, pve) | 10.40.20.20 | SSH via pve (`pct exec 105 --`) · **TP20 ✅ 2026-07-16: PG16, DB `nautobot`, Creds `postgres/.secrets`** | @@ -70,10 +71,13 @@ GW je VLAN = `.1` (crs326-core L3) · Mgmt VLAN99: core `.99.1`, branch `.99.2`, - 📜 **~~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). - **Mesh = NEIN** (beide APs haben wired Trunk-Uplink → Loop-Risiko). -- **Beide APs = Standalone mit `vlan-filtering=yes`, KEIN CAPsMAN (TP3-Rebuild ✅ 2026-08-08):** `datapath.vlan-id` landet nur mit vlan-filtering auf der Leitung. Nur Master-Radios wifi1/wifi2 sind Bridge-Ports (Slave-VAPs forwarden darüber) → **wifi1/wifi2 müssen tagged-Member je Client-VLAN sein**. Uplink=`ether1` (PoE), VLAN1 untagged=Fallback. Jede SSID-config braucht `datapath` (sonst egress ungetaggt in VLAN1 = das alte TP3.1-Leck). **Falle bei Neu-Provisionierung:** Werks-Inline-Overrides auf wifi1/wifi2 (`configuration.ssid=MikroTik-*`, `security.*`) überschreiben das verlinkte Profil → nach `/import` mit `!configuration.ssid !security.*` leeren. Configs `routeros/.secrets/ap{1,2}-prov-base.rsc`. +- **Beide APs = CAPs, Manager ist `crs326-core` (TP28 ✅ 2026-08-17).** Der Entscheid „kein CAPsMAN" von 2026-07-22 ist **revidiert**: er galt der Konstellation ap1=Manager+AP, in der ein Manager seine eigenen Radios nicht provisionieren kann — mit dem Core als Manager sind beide APs symmetrisch. Der Core braucht dafür **kein** `wifi-qcom`, `capsman` steckt im Basispaket. + - 🔴 **Messfalle: unter CAPsMAN führt der MANAGER die Tabellen.** `/interface/wifi/registration-table` und die `wireless`-Logs sind auf ap1/ap2 **leer**, obwohl das WLAN läuft. **Immer am Manager zählen.** + - 🔴 **Die CAPs finden den Manager per Layer-2-Discovery** (`discovery-interfaces=vlan99`, `current-caps-man-address` ist eine **MAC**, keine IP). Deshalb müssen **MNDP (udp/5678)** und **CAPWAP (udp/5246-5247)** in der `input`-Kette des Core erlaubt bleiben — sonst kommt das WLAN nach dem nächsten AP-Reboot nicht zurück, während laufende Sessions unauffällig weiterlaufen (Fund 2026-08-18, TP5 Etappe 4). + - **Local Forwarding ist keine Einstellung mehr:** im neuen `/interface/wifi` gibt es kein zentrales Forwarding, `datapath` existiert dort nicht. - mgmt-VLAN-Wechsel am Switch = Lockout-Risiko: VLAN muss existieren + Port muss es tragen, in einem Schritt. - 📜 **~~Omada ES208G = Easy Managed~~ — gegenstandslos** (Gerät abgebaut 2026-07-23, Controller gelöscht). -- **L3-Router = `crs326-core` (TP21.1 ✅ 2026-08-08, ersetzt ap1).** Bridge vlan-filtering=yes; VLAN-SVIs `.1` je VLAN mit DHCP (7 Server / 54 Leases); DNS aktuell **plain `1.1.1.1`** (DoH-Cloudflare-Gateway-TODO, core hat kein CA). **ap1/ap2 sind NUR noch APs** — kein DHCP/DNS/NAT/Routing/WG dort. (Die frühere „TP4: ap1 ist L3-Router"-Zeile ist überholt.) +- **L3-Router = `crs326-core` (TP21.1 ✅ 2026-08-08, ersetzt ap1).** Bridge vlan-filtering=yes; VLAN-SVIs `.1` je VLAN mit DHCP (7 Server / 54 Leases); DNS über **DoH** zum CF-Gateway, `verify-doh-cert=yes` (TP23 Stufe 1 ✅ 2026-08-18). Die alte Notiz „core hat kein CA" war zu pessimistisch: es braucht kein Bundle, sondern **genau einen Root** (GTS Root R4, ~1 KB) — die Kette ist Leaf → GTS WE1 → R4. **Beide Firewall-Ketten enden seit 2026-08-18 mit `drop`** (TP5 E3/E4); `TP10-seal-lan` ist `disabled`, Mgmt-Input kommt nur noch aus VLAN10, von HA (`8728`), von Nautobot (`22`) und über `cf-mesh`. **ap1/ap2 sind NUR noch APs** — kein DHCP/DNS/NAT/Routing/WG dort. (Die frühere „TP4: ap1 ist L3-Router"-Zeile ist überholt.) - **✅✅ Edge-Cutover (2026-07-01; Router-Umzug 2026-08-08): FritzBox ausgebaut, Arris im Bridge-Mode.** Liwest hat die FB6660 dauerhaft gegen ein Arris getauscht (physisch weg). WAN terminiert auf **`crs326-core vlan100`** (VLAN100-Transfer), core zieht die öffentliche Liwest-IP `90.146.33.177` → kein Double-NAT. **core = Public-Edge + WG-Hub** (fm/dw live), NICHT mehr ap1. Telefonie nicht weitergeführt. Runbook `routeros/wan-cutover-runbook.md` (ap1-Teile historisch). - **hAP `device-mode=home` (ap1/ap2): scheduler + fetch blockiert** (`not allowed by device-mode`) → AP-Provisionierung idempotent **ohne** Scheduler. **`[/ping]` gibt nil in 7.23**. REST je AP `http://10.40.99.11|12/rest` (Creds = `ROUTER_AP{1,2}` in `~/.claude.json`). **Der L3-Router crs326-core ist KEIN device-mode=home** → dort gehen scheduler/fetch (z.B. DDNS-Updater). - **Erstzugriff Werks-hAP am CRS-Fabric:** Uplink `ether1` = Werks-WAN → `192.168.88.1` (LAN) darüber NICHT erreichbar. Weg: Gerät auf **LAN-Port (ether2)** patchen ODER **Core-Temp-Pfad** `192.168.88.2/24` auf core-`bridge` + srcnat masq `192.168.88.0/24`, dann scp+`/import` (danach Temp-Pfad + stale ARP `.88.1` entfernen). Winbox-Neighbors zeigt die APs NICHT (MNDP pro-VLAN, Mgmt auf vlan99) — kein L2-Fehler. diff --git a/docs/routerboot-firmware-klickanleitung.md b/docs/routerboot-firmware-klickanleitung.md new file mode 100644 index 0000000..f759c0f --- /dev/null +++ b/docs/routerboot-firmware-klickanleitung.md @@ -0,0 +1,98 @@ +# RouterBOOT-Firmware auf 7.24 nachziehen — Klickanleitung (WinBox) + +**Stand 2026-08-18, live erhoben.** RouterOS ist auf allen vier Geräten bereits 7.24. +Zurück hängt nur der **Bootloader** (RouterBOOT): + +| Gerät | IP | Modell | aktuell | Ziel | +|---|---|---|---|---| +| `crs326-core` | 10.40.99.1 | CRS326-24G-2S+ | **7.19.5** | 7.24 | +| `crs326-branch` | 10.40.99.2 | CRS326-24G-2S+ | **7.19.5** | 7.24 | +| `ap1` | 10.40.99.11 | hAP ax² | **7.23.2** | 7.24 | +| `ap2` | 10.40.99.12 | hAP ax² | **7.23.2** | 7.24 | + +--- + +## Warum das per Hand geht und nicht über die Automatik + +`/system routerboard upgrade` **fragt interaktiv nach** („Do you really want to upgrade +firmware?"). Damit fällt es durch beide Wege raus, die dieses Netz sonst nutzt: + +- **MikroMCP** blockt den Befehl per Deny-Policy (er schreibt den Bootloader). +- **Nautobot Golden Config** schickt die Zeile per Netmiko ab, bekommt den Prompt statt einer + Antwort und quittiert mit `E3001` und **leerer** Fehlermeldung. Am 2026-08-17 genau so + passiert — es wurde nichts geschrieben, aber auch nichts gemeldet. + +Auf `core` und `branch` ginge ein Umweg über den Scheduler (dort läuft kein +`device-mode=home`). Auf **ap1/ap2 nicht** — dort ist der Scheduler gesperrt. Für vier +Geräte ist der Klickweg schlicht der ehrlichere. + +--- + +## Die Klicks (identisch auf jedem Gerät) + +1. **WinBox öffnen** → Reiter **Neighbors** → Gerät in der Liste doppelklicken + (oder unter *Connect To* die IP aus der Tabelle oben eintippen). + Login `admin`, Passwort aus `~/.secrets` (auf allen vier gleich). +2. Links im Menü **System** → **RouterBOARD**. +3. Im Fenster stehen zwei Zeilen: + - `Current Firmware: 7.19.5` (bzw. `7.23.2`) + - `Upgrade Firmware: 7.24` + ➡️ **Stehen beide auf 7.24, ist das Gerät fertig — Fenster zu, nächstes Gerät.** +4. Oben auf den Knopf **Upgrade** klicken. +5. Rückfrage **„Do you really want to upgrade firmware?"** → **Yes**. +6. Es erscheint sinngemäß *„Firmware upgraded, reboot for changes to take effect"*. + **Die Firmware ist damit geschrieben, aber noch nicht aktiv.** +7. Links im Menü **System** → **Reboot** → **Yes**. +8. Warten (CRS326 ~40 s, hAP ~60 s), neu verbinden, **System → RouterBOARD** öffnen: + `Current Firmware` muss jetzt **7.24** sein. + +> **Schritt 7 nicht vergessen.** Ohne Reboot bleibt `Current Firmware` auf dem alten Wert, +> und beim nächsten Blick sieht es aus, als hätte der Upgrade nicht funktioniert. + +--- + +## Reihenfolge — und was dabei jeweils ausfällt + +Von harmlos nach heikel. Jedes Gerät erst abschließen (inkl. Reboot und Gegenprobe), +bevor das nächste drankommt. + +| # | Gerät | Was während des Reboots weg ist | Dauer | +|---|---|---|---| +| 1 | **ap1** | WLAN im UG. Clients wechseln auf ap2, Roaming fängt das ab. | ~60 s | +| 2 | **ap2** | WLAN im OG, dazu kurz die Shellys. Sie kommen von selbst zurück. | ~60 s | +| 3 | **crs326-core** | ⚠️ **Alles**: Routing, DHCP, DNS, Internet, WireGuard, CAPsMAN-Manager. | ~40 s | +| 4 | **crs326-branch** | ⚠️ **Deine LAN-Verbindung** (dein Arbeitsplatz hängt daran) + NAS/Drucker/macmini. | ~40 s | + +**branch bewusst zuletzt:** dein Rechner hängt per Kabel daran. Wenn dabei etwas schiefgeht, +sind alle anderen Geräte schon nachweislich oben — und der Fehler ist damit eingegrenzt. + +**Beim Core:** WLAN und LAN laufen weiter (die APs sind CAPs und behalten ihre Konfiguration, +die Switches schalten Layer 2 unabhängig), aber es gibt für die Dauer des Reboots **kein DHCP, +kein DNS und kein Internet**. Kein guter Moment für ein Telefonat. + +--- + +## Gegenprobe hinterher (statt Klicken) + +Alle vier auf einmal, ohne WinBox: + +```bash +cd ~/dev/bf-network-r6 && for s in "core:10.40.99.1:CRS326_CORE_PASS" "branch:10.40.99.2:CRS326_BRANCH_PASS" "ap1:10.40.99.11:ROUTER_AP1_PASS" "ap2:10.40.99.12:ROUTER_AP2_PASS"; do n=${s%%:*}; r=${s#*:}; ip=${r%%:*}; v=${r##*:}; p=$(grep -E "^(export )?$v=" ~/.secrets/credentials.env | head -1 | sed -E "s/^(export )?$v=//" | tr -d "\"'"); curl -s -u "admin:$p" --max-time 8 "http://$ip/rest/system/routerboard" | python3 -c "import json,sys;d=json.load(sys.stdin);print(f' $n current={d.get(\"current-firmware\")} upgrade={d.get(\"upgrade-firmware\")}')"; done +``` + +**Soll:** bei allen vier `current=7.24 upgrade=7.24`. + +--- + +## Wenn etwas klemmt + +- **Gerät kommt nach dem Reboot nicht zurück** → 2–3 Minuten geben (RouterBOOT prüft nach + einem Firmware-Wechsel beim ersten Start mehr als sonst). Danach: Strom aus/an. +- **`Current Firmware` bleibt alt** → Reboot wurde übersprungen, Schritt 7 nachholen. +- **Kein `Upgrade`-Knopf sichtbar** → das Gerät ist bereits aktuell. +- **Netz nach dem Core-Reboot still** → erst prüfen, ob es wirklich am Core liegt: + `ping 10.40.99.1`. Antwortet er, ist Layer 3 zurück und der Rest hängt an DHCP-Leases, + die sich von selbst erneuern. + +⚠️ **Nicht während des Vorgangs** parallel Golden-Config-Deploys laufen lassen — ein Reboot +mitten im Netmiko-Push hinterlässt einen Teil-Zustand (bekannte TP22-Falle). diff --git a/nautobot/ingest-core-firewall.py b/nautobot/ingest-core-firewall.py index dd9d89a..be924b2 100644 --- a/nautobot/ingest-core-firewall.py +++ b/nautobot/ingest-core-firewall.py @@ -32,7 +32,13 @@ DEVICE = "crs326-core" SECRETS = pathlib.Path.home() / ".secrets" / "credentials.env" # Felder, die RouterOS im Export NICHT schreibt (Laufzeit-/Interndaten). -SKIP = {".id", "dynamic", "invalid", "bytes", "packets", "creation-time"} +# `hw-offload` gehoert dazu (2026-08-18 aufgeschlagen): die REST-API meldet es +# auf der defconf-fasttrack-Regel als true, `/ip firewall filter export` laesst +# es weg -- am Geraet gegengeprueft. Ohne diesen Eintrag meldet die Compliance +# ewige Falsch-Drift auf genau dieser einen Regel. Gleiche Klasse wie die +# `disabled=false`- und Boolean-Faelle weiter unten. +SKIP = {".id", "dynamic", "invalid", "bytes", "packets", "creation-time", + "hw-offload"} def secret(key): diff --git a/nautobot/mikrotik_routeros.j2 b/nautobot/mikrotik_routeros.j2 index 3cd6f01..31d5362 100644 --- a/nautobot/mikrotik_routeros.j2 +++ b/nautobot/mikrotik_routeros.j2 @@ -20,12 +20,16 @@ # winbox war auf ALLEN vier unbeschraenkt. # ⚠️ Lockout-Regel: 10.40.0.0/16 (LAN) UND 100.96.0.0/12 (Mesh) muessen beide drin sein — # das sind die zwei Wege, ueber die dieses Netz administriert wird. Nie einen davon kappen. +# ⚠️ Attribut heisst `available-from`, NICHT `address` (korrigiert 2026-08-18): RouterOS +# 7.23/7.24 exportiert `available-from=`, das Template schrieb `address=`. Ergebnis waren +# vier Dauer-Drifts (ap1/ap2/branch/core), bei denen das GERAET recht hatte und das Soll +# falsch war. Beim Push haette `address=` auf 7.24 zudem auflaufen koennen. /ip service set ftp disabled=yes -/ip service set ssh address=10.40.0.0/16,100.96.0.0/12 +/ip service set ssh available-from=10.40.0.0/16,100.96.0.0/12 /ip service set telnet disabled=yes -/ip service set www address=10.40.0.0/16,100.96.0.0/12 -/ip service set winbox address=10.40.0.0/16,100.96.0.0/12 -/ip service set api address=10.40.0.0/16,100.96.0.0/12 +/ip service set www available-from=10.40.0.0/16,100.96.0.0/12 +/ip service set winbox available-from=10.40.0.0/16,100.96.0.0/12 +/ip service set api available-from=10.40.0.0/16,100.96.0.0/12 /ip service set api-ssl disabled=yes {% if obj.name == "crs326-core" %} @@ -124,9 +128,19 @@ {% endfor %} /ip dhcp-server option add code=6 name="dns 1.1.1.1" value=0x01010101 -# [6] DNS — Upstream aktuell PLAIN 1.1.1.1. DoH-Cloudflare-Gateway ist offener TODO -# (core hat kein CA-Bundle -> verify-doh-cert nicht moeglich), s. TP21.1. -/ip dns set allow-remote-requests=yes mdns-repeat-ifaces=vlan10,vlan20,vlan40,vlan30,vlan90 servers=1.1.1.1 +# [6] DNS — DoH zum Cloudflare-Gateway, MIT Zertifikatspruefung (TP23 Stufe 1, +# scharf seit 2026-08-18; schliesst TP21.1 TODO 1). +# `servers=1.1.1.1` BLEIBT als Bootstrap stehen: RouterOS loest den +# DoH-Hostnamen selbst darueber auf, sonst Henne-Ei. Alles andere geht +# ueber DoH. +# Die frueher hier notierte Begruendung "core hat kein CA-Bundle" war zu +# pessimistisch: es braucht kein Bundle, sondern genau EINEN Root. Die Kette +# ist Leaf -> GTS WE1 -> GTS Root R4, importiert ist nur R4 (~1 KB, gueltig +# bis 2036) — entscheidend bei 2,8 MB freiem Flash. +# Der Import selbst steht bewusst NICHT im Template: er braucht die Datei +# auf dem Geraet und ist ein einmaliger Bootstrap, kein Sollzustand. +# Artefakt: routeros/tp23-stufe1-doh-core.rsc +/ip dns set allow-remote-requests=yes mdns-repeat-ifaces=vlan10,vlan20,vlan40,vlan30,vlan90 servers=1.1.1.1 use-doh-server=https://px35ynlol3.cloudflare-gateway.com/dns-query verify-doh-cert=yes # Kanonischer Mgmt-Nummernplan (User-Bestaetigung 2026-08-13, verbindlich): # core .99.1 | branch .99.2 | ap1 .99.11 | ap2 .99.12 diff --git a/routeros/tp19-ntp-branch-client.rsc b/routeros/tp19-ntp-branch-client.rsc new file mode 100644 index 0000000..6511465 --- /dev/null +++ b/routeros/tp19-ntp-branch-client.rsc @@ -0,0 +1,5 @@ +# NTP-Client auf crs326-branch nachziehen. Er hatte GAR KEINEN Server +# eingetragen (status=stopped) — die Uhr stimmte nur zufaellig noch. +# Zeitquelle ist der Core (s. routeros/tp19-ntp-core-als-zeitquelle.rsc). +:do { /system ntp client set enabled=yes servers=10.40.99.1 } on-error={ :log info "tp19ntp: branch warf" } +:log info ("tp19ntp: branch status=" . [/system ntp client get status]) diff --git a/routeros/tp19-ntp-core-als-zeitquelle.rsc b/routeros/tp19-ntp-core-als-zeitquelle.rsc new file mode 100644 index 0000000..fbf03bf --- /dev/null +++ b/routeros/tp19-ntp-core-als-zeitquelle.rsc @@ -0,0 +1,34 @@ +# NTP: den Core zur Zeitquelle des Standorts machen. +# +# BEFUND (2026-08-18, beim TP19-Abschluss gefunden): +# ap1 ntp client -> 10.40.99.1, status=waiting, Uhr zufaellig noch richtig +# ap2 ntp client -> 10.40.99.1, status=waiting, Uhr **17 Stunden nach** +# branch ntp client -> gar keiner, status=stopped +# core /system ntp server = enabled:no +# Alle drei fragen also einen Zeitserver, den es nicht gibt ("waiting" heisst +# genau das). ap2 ist nur der erste, der sichtbar weggelaufen ist — die anderen +# folgen. +# +# WARUM DAS MEHR ALS KOSMETIK IST: Geraete-Logs sind das Hauptwerkzeug in diesem +# Projekt (TP5 lebt vom Kollektor). Beim Pfadbeweis heute nacht hat ap2 einen +# Logeintrag von 04:57 als "2026-08-17 12:19" gestempelt — eine Korrelation +# ueber mehrere Geraete ist damit wertlos. +# +# WEG: der Core hat als einziger eine verlaessliche Zeit (WAN + DoH). Er wird +# Server, die drei anderen bleiben/werden Clients auf 10.40.99.1. Kein Geraet +# braucht dafuer Internet. +# +# ⚠️ Die input-Regel ist Pflicht: seit Etappe 4 endet `input` mit einem Drop. +# Ohne sie waere der NTP-Server eingeschaltet und trotzdem unerreichbar — +# derselbe stille Fehlschlag wie bisher, nur eine Ebene tiefer. +# +# Push: python3 nautobot/gc-manual-plan.py --device crs326-core \ +# --commands-file routeros/tp19-ntp-core-als-zeitquelle.rsc \ +# --change-id TP19-NTP --deploy \ +# --assert '/system/ntp/server|enabled=true' +# --------------------------------------------------------------------------- + +:do { /system ntp server set enabled=yes } on-error={ :log info "tp19ntp: 01 server warf" } +:do { :if ([:len [/ip firewall filter find comment="TP5-E4: ntp"]] = 0) do={ /ip firewall filter add chain=input action=accept in-interface-list=LAN protocol=udp dst-port=123 comment="TP5-E4: ntp" place-before=[/ip firewall filter find comment="TP5: input log-only"] } } on-error={ :log info "tp19ntp: 02 fw warf" } + +:log info ("tp19ntp: ENDE server-enabled=" . [:tostr [/system ntp server get enabled]] . " fw-regel=" . [:tostr [:len [/ip firewall filter find comment="TP5-E4: ntp"]]]) diff --git a/routeros/tp5-etappe3-autorevert-abbestellen.rsc b/routeros/tp5-etappe3-autorevert-abbestellen.rsc new file mode 100644 index 0000000..07eebe8 --- /dev/null +++ b/routeros/tp5-etappe3-autorevert-abbestellen.rsc @@ -0,0 +1,14 @@ +# TP5 Etappe 3 — Auto-Revert abbestellen. +# +# Der Scheduler aus tp5-etappe3-drop.rsc haette den Drop nach 10 Minuten selbst +# wieder abgeschaltet. Die Abnahme ist durch, also wird er entfernt und der +# Drop bleibt stehen. Abnahme am 2026-08-18 (Drop live): +# INFRA->IOT Shelly .30.211:80 = 200 +# INFRA->WAN cloudflare.com = 301 +# INFRA->MAIN MacBook = erreichbar +# INFRA->MGMT branch:22 von pve = ZU (korrekt: pve ist keine Mgmt-Quelle) +# GC-Deploy nautobot-worker -> ap2:22 = SUCCESS (der Pfadbeweis) +# Gedroppt wurden in der Testphase 11 Pakete — ausschliesslich die eigene +# pve->branch:22-Sonde. +:do { /system scheduler remove [find name="tp5autorevert"] } on-error={ :log info "tp5e3: abbestellen warf" } +:log info ("tp5e3: AUTO-REVERT entfernt, drop-disabled=" . [:tostr [/ip firewall filter get [find comment="TP5: deny-by-default"] disabled]]) diff --git a/routeros/tp5-etappe4-autorevert-abbestellen.rsc b/routeros/tp5-etappe4-autorevert-abbestellen.rsc new file mode 100644 index 0000000..04f907c --- /dev/null +++ b/routeros/tp5-etappe4-autorevert-abbestellen.rsc @@ -0,0 +1,13 @@ +# TP5 Etappe 4 — Auto-Revert abbestellen. Abnahme 2026-08-18 (input-Drop live): +# DNS aus VLAN20 an den Core core.bf.lan -> 10.40.99.1, heise.de -> 193.99.144.80 +# AGH unveraendert nas.bf.lan -> 10.40.20.10 +# MAIN->core admin 57 Pakete (MikroMCP/SSH laufen weiter) +# HA->core api 3 Pakete +# Die 5 mDNS-input-Regeln erstmals scharf: vlan30=87, vlan20=13 Pakete +# (standen seit dem Bau am 2026-08-14 auf 0) +# CAPsMAN ap1 + ap2 state=Ok +# Gedroppt wurde ausschliesslich Broadcast-Rauschen, fuer das der Core nie +# zustaendig war: MNDP (inzwischen explizit erlaubt), NetBIOS 137/138 aus +# VLAN20, SSDP-Announcements einer Sonos aus VLAN40. +:do { /system scheduler remove [find name="tp5e4autorevert"] } on-error={ :log info "tp5e4: abbestellen warf" } +:log info ("tp5e4: AUTO-REVERT entfernt, input-drop-disabled=" . [:tostr [/ip firewall filter get [find comment="TP5: input deny-by-default"] disabled]] . " seal-lan-disabled=" . [:tostr [/ip firewall filter get [find comment="TP10-seal-lan"] disabled]]) diff --git a/routeros/tp5-etappe4-nachtrag-discovery.rsc b/routeros/tp5-etappe4-nachtrag-discovery.rsc new file mode 100644 index 0000000..88d7212 --- /dev/null +++ b/routeros/tp5-etappe4-nachtrag-discovery.rsc @@ -0,0 +1,32 @@ +# TP5 Etappe 4 — NACHTRAG: Discovery-Protokolle in den input lassen. +# +# BEFUND (2026-08-18, unmittelbar nach dem input-Drop): +# Die input-Log-Regel fing MNDP-Broadcasts (udp/5678) von crs326-branch +# (04:F4:1C:B4:15:58), ap1 (D0:EA:11:4D:40:E0/E1) und ap2 (D0:EA:11:4D:40:39/3A). +# +# WARUM DAS NICHT HARMLOS IST: +# `/interface/wifi/cap` auf ap1 zeigt +# discovery-interfaces: vlan99 +# current-caps-man-address: 04:F4:1C:B4:17:76%vlan99 +# — eine MAC, keine IP. Die CAPs finden ihren Manager also per Layer-2-Discovery +# auf vlan99, nicht ueber eine konfigurierte Adresse. Ein Drop dieser Pakete +# bricht die Manager-Findung. Die BESTEHENDEN CAPWAP-Sitzungen laufen weiter +# (sie sind established und werden von TP10-seal-est akzeptiert), das Problem +# schlaegt also erst beim naechsten AP- oder Manager-Neustart zu — genau die +# Sorte Spaetschaden, die man im Log sehen und sofort schliessen will. +# +# Sicherheitlich billig: MNDP ist link-lokal (Broadcast, verlaesst das Segment +# nicht), CAPWAP wird auf vlan99 begrenzt. +# +# ⚠️ place-before ist Pflicht: ein blankes `add` haengt hinter den Drop und +# waere wirkungslos. +# --------------------------------------------------------------------------- + +# MNDP. Aus der LAN-Liste, weil es auch die Winbox-Neighbors-Anzeige speist und +# als Broadcast ohnehin nicht routbar ist. +:do { :if ([:len [/ip firewall filter find comment="TP5-E4: MNDP discovery"]] = 0) do={ /ip firewall filter add chain=input action=accept in-interface-list=LAN protocol=udp dst-port=5678 comment="TP5-E4: MNDP discovery" place-before=[/ip firewall filter find comment="TP5: input log-only"] } } on-error={ :log info "tp5e4n: 01 mndp warf" } + +# CAPsMAN/CAPWAP, eng auf das Mgmt-VLAN begrenzt. +:do { :if ([:len [/ip firewall filter find comment="TP5-E4: CAPsMAN capwap"]] = 0) do={ /ip firewall filter add chain=input action=accept in-interface=vlan99 protocol=udp dst-port=5246,5247 comment="TP5-E4: CAPsMAN capwap" place-before=[/ip firewall filter find comment="TP5: input log-only"] } } on-error={ :log info "tp5e4n: 02 capwap warf" } + +:log info ("tp5e4n: ENDE mndp=" . [:tostr [:len [/ip firewall filter find comment="TP5-E4: MNDP discovery"]]] . " capwap=" . [:tostr [:len [/ip firewall filter find comment="TP5-E4: CAPsMAN capwap"]]])