Initial commit: BF Core-Switch-Prep + VLAN-Architektur + Delegations-Übergabe
- ALL-SG8316M auf FW 2.2.1.2956 geflasht; VLAN-DB 10/20/30/40/100 via Telnet-CLI (non-disruptiv) - CLI-Tooling: run-cli.exp + .cli-Files + CLI-REFERENCE (FW 2.2.1, IOS-artig) - Kanonisches Inventar: bf.csv/md + build.py (Doku-Motor), Core-Port-Map - Finaler VLAN-/Adressplan (10.40.<vlanid>.0/24), Firmware-Runbooks, Recovery-Assets - Secrets/Firmware/State/DS_Store via .gitignore ausgeschlossen Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
5
switch/.gitignore
vendored
Normal file
5
switch/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.secrets
|
||||
cookies.txt
|
||||
state-*/
|
||||
firmware/
|
||||
cli/running-*.txt
|
||||
4
switch/.secrets.example
Normal file
4
switch/.secrets.example
Normal file
@@ -0,0 +1,4 @@
|
||||
# copy to .secrets (gitignored). Account = Web/Telnet login on the switch.
|
||||
export SW_HOST=10.40.41.239
|
||||
export SW_USER=claudecode
|
||||
export SW_PASS=changeme
|
||||
8
switch/cli/01-vlan-db.cli
Normal file
8
switch/cli/01-vlan-db.cli
Normal file
@@ -0,0 +1,8 @@
|
||||
# === BF Core-Switch sw1 (ALL-SG8316M, FW 2.2.1) — VLAN-Datenbank ===
|
||||
# Reproduzierbar: . switch/.secrets && expect switch/cli/run-cli.exp switch/cli/01-vlan-db.cli
|
||||
# NON-DISRUPTIV: legt nur VLANs an; ändert KEINE Port-Zugehörigkeit (alle Ports bleiben default VLAN1).
|
||||
# VID-Plan: 10=Server/Main 20=Docker 30=IoT 40=Guest 100=WAN
|
||||
configure
|
||||
vlan 10,20,30,40,100
|
||||
end
|
||||
save
|
||||
47
switch/cli/CLI-REFERENCE.md
Normal file
47
switch/cli/CLI-REFERENCE.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# ALL-SG8316M FW 2.2.1.2956 — CLI-Referenz (Telnet)
|
||||
|
||||
Switch `sw1` @ 10.40.41.239. **Kein SSH** → Telnet (Port 23). IOS-artige CLI. Login: `claudecode` (Creds in `switch/.secrets`).
|
||||
Prompt-Ebenen: `sw1>` (user) → `sw1#` (enable) → `sw1(config)#` (config). `configure` rein, `end`/`exit` raus.
|
||||
|
||||
> ⚠️ **Nur EINE VTY-Line!** Der Switch reapt halb-offene Sessions schlecht (stale Session sperrt ~15 min).
|
||||
> → Immer **serialisiert** arbeiten und **sauber ausloggen** (`exit` bis zur Verbindungstrennung). Bei „busy" **nicht hämmern**, paar Minuten warten.
|
||||
|
||||
Tooling (macOS): `telnet` (/opt/homebrew/bin) + `expect`. Python 3.14 hat KEIN telnetlib. Runner: `switch/cli/run-cli.exp <file.cli>`.
|
||||
|
||||
## Management-IP
|
||||
- **Ansehen** (enable): `show ip` → IP / Subnet Netmask / Default Gateway.
|
||||
- `show ip ?`: `dhcp dns http https igmp` (+ `<cr>` = Summary).
|
||||
- **Statisch setzen** (config):
|
||||
```
|
||||
ip address <A.B.C.D>
|
||||
ip default-gateway <A.B.C.D>
|
||||
```
|
||||
- ⚠️ **Netzmasken-Syntax noch zu bestätigen**: `ip address ?` zeigte nur `A.B.C.D`. Vor dem Commit
|
||||
`ip address <ip> ?` prüfen ODER `show running-config` ansehen (wie die bestehende Zeile geschrieben ist) und spiegeln.
|
||||
- DHCP statt statisch: `ip dhcp`.
|
||||
- **NICHT vorhanden:** `interface vlan`, `show ip interface`, `show management`, `terminal datadump`.
|
||||
|
||||
## Management-VLAN
|
||||
- **Setzen** (config): `management-vlan vlan <1-4094>` (`management` = Abk.)
|
||||
- **Ansehen** (enable): `show management-vlan` → aktuell `default(1)`.
|
||||
- Reihenfolge-Warnung: Ziel-VLAN muss existieren UND der Mgmt-Port muss es tragen, sonst Reachability weg.
|
||||
|
||||
## VLANs
|
||||
- **Anlegen** (config): `vlan <liste>` z.B. `vlan 10,20,30,40,100` (Range 1–4094, `3,6-8` möglich).
|
||||
- **Ansehen** (enable): `show vlan`.
|
||||
- **Namen:** Syntax noch zu erkunden (config-vlan `name`? `vlan <id>` einzeln?) — beim nächsten Lauf via `?` prüfen.
|
||||
|
||||
## Ports (gi1-16, lag1-8) — Trunk/Access (für Cutover)
|
||||
```
|
||||
interface gi<n> (oder: interface range ...)
|
||||
switchport mode {access|hybrid|trunk}
|
||||
switchport access vlan <id>
|
||||
switchport trunk native vlan <id>
|
||||
switchport trunk allowed vlan ... (genaue add/remove-Syntax via `switchport trunk allowed ?` prüfen)
|
||||
```
|
||||
|
||||
## Speichern / Diverses
|
||||
- **Persistieren:** `save` (enable) → „Success". (Sonst nach Reboot weg!)
|
||||
- **Config-Dump:** `show running-config` / `show startup-config` (Paging `--More--` → Space).
|
||||
- **Version:** `show version` → `Firmware Version : 2.2.1.2956`.
|
||||
- Andere: `reboot`, `restore-defaults`, `copy`, `clock`, `ping`, `ssl`, `clear`, `disable`, `terminal`.
|
||||
33
switch/cli/run-cli.exp
Normal file
33
switch/cli/run-cli.exp
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/expect -f
|
||||
# Generischer Telnet-CLI-Runner für sw1 (ALL-SG8316M, FW 2.2.1, IOS-artige CLI).
|
||||
# Nutzung: . switch/.secrets && expect switch/cli/run-cli.exp switch/cli/<datei>.cli
|
||||
# Liest die .cli-Datei zeilenweise, loggt ein, sendet jeden Befehl, flaggt Fehler.
|
||||
# Zeilen mit führendem '#' = Kommentar (übersprungen). Am Ende: show vlan zur Kontrolle.
|
||||
set timeout 20
|
||||
set user $env(SW_USER)
|
||||
set pass $env(SW_PASS)
|
||||
set host $env(SW_HOST)
|
||||
if {[llength $argv] < 1} { puts "usage: run-cli.exp <file.cli>"; exit 1 }
|
||||
set fh [open [lindex $argv 0] r]
|
||||
log_user 1
|
||||
spawn telnet $host
|
||||
expect "Username:"; send "$user\r"
|
||||
expect "Password:"; send "$pass\r"
|
||||
expect -re {sw1[#>]}
|
||||
while {[gets $fh line] >= 0} {
|
||||
set line [string trim $line]
|
||||
if {$line eq "" || [string match "#*" $line]} { continue }
|
||||
send "$line\r"
|
||||
expect {
|
||||
"Incomplete command" { puts "\n>>> FEHLER (incomplete): $line" }
|
||||
"Unknown command" { puts "\n>>> FEHLER (unknown): $line" }
|
||||
-re {sw1\([^)]*\)[#>] ?$} {}
|
||||
-re {sw1[#>] ?$} {}
|
||||
timeout { puts "\n>>> TIMEOUT bei: $line" }
|
||||
}
|
||||
}
|
||||
close $fh
|
||||
send "show vlan\r"
|
||||
expect -re {sw1[#>]}
|
||||
send "exit\r"
|
||||
expect eof
|
||||
41
switch/recovery/README.md
Normal file
41
switch/recovery/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Mac-mini Recovery-Anker für den Switch-Flash
|
||||
|
||||
**Zweck:** Der Mac mini (10.40.41.167, en0, L2-benachbart zum Switch) trägt dauerhaft eine
|
||||
**Zweit-IP 192.168.1.2/24**. Nach einem Firmware-Flash kommt der Switch auf `192.168.1.1` hoch
|
||||
(Werks-Default) — über die Zweit-IP erreicht Claude ihn **vom Mac mini aus** und setzt ihn
|
||||
automatisch auf `10.40.41.239` zurück. Kein manuelles IP-Suchen, kein Laptop nötig.
|
||||
|
||||
## Variante A — nur für heute (transient, kein Reboot dazwischen)
|
||||
Auf dem Mac mini (deine SSH-Session):
|
||||
```
|
||||
sudo ifconfig en0 alias 192.168.1.2 255.255.255.0
|
||||
ifconfig en0 | grep 192.168.1 # prüfen
|
||||
```
|
||||
Entfernen: `sudo ifconfig en0 -alias 192.168.1.2`
|
||||
|
||||
## Variante B — persistent (übersteht Reboots, empfohlen wenn Dauer-Anker)
|
||||
Auf dem Mac mini, aus diesem Repo-Ordner (`switch/recovery/`):
|
||||
```
|
||||
sudo cp switch-recovery-ip.sh /usr/local/sbin/switch-recovery-ip.sh
|
||||
sudo chmod 755 /usr/local/sbin/switch-recovery-ip.sh
|
||||
sudo cp com.bf.switchrecoveryip.plist /Library/LaunchDaemons/
|
||||
sudo chown root:wheel /Library/LaunchDaemons/com.bf.switchrecoveryip.plist
|
||||
sudo launchctl load -w /Library/LaunchDaemons/com.bf.switchrecoveryip.plist
|
||||
ifconfig en0 | grep 192.168.1 # prüfen
|
||||
```
|
||||
Deinstallieren:
|
||||
```
|
||||
sudo launchctl unload -w /Library/LaunchDaemons/com.bf.switchrecoveryip.plist
|
||||
sudo rm /Library/LaunchDaemons/com.bf.switchrecoveryip.plist /usr/local/sbin/switch-recovery-ip.sh
|
||||
sudo ifconfig en0 -alias 192.168.1.2
|
||||
```
|
||||
|
||||
## Recovery-Ablauf nach Flash (Claude führt aus, vom Mac mini)
|
||||
```
|
||||
ssh 10.40.41.167
|
||||
cd ~/.../bf-network-r6/switch # Repo muss auf dem Mac mini liegen ODER Claude tunnelt
|
||||
SW_HOST=192.168.1.1 SW_USER=admin SW_PASS=admin ./sg8316m.sh set-ip 10.40.41.239
|
||||
# Switch nun wieder auf .239 → .secrets zurück, dann VLANs/Ports/save
|
||||
```
|
||||
> Hinweis: Claude erreicht den Switch nach Flash **nur** über den Mac mini (.1.1 ist L2-lokal am Mac mini).
|
||||
> Der Treiber `sg8316m.sh` muss daher vom Mac mini aus laufen (Repo dorthin klonen/kopieren oder via SSH ausführen).
|
||||
16
switch/recovery/com.bf.switchrecoveryip.plist
Normal file
16
switch/recovery/com.bf.switchrecoveryip.plist
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.bf.switchrecoveryip</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/sbin/switch-recovery-ip.sh</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/log/switch-recovery-ip.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
136
switch/recovery/flash-and-recover.sh
Normal file
136
switch/recovery/flash-and-recover.sh
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/bin/sh
|
||||
# Autonome Flash- + Recovery-Orchestrierung für ALL-SG8316M.
|
||||
# LÄUFT AUF DEM MAC MINI (10.40.41.167, en0, L2-lokal zum Switch).
|
||||
# Zweck: Claude stößt es detached an und ist während des Switch-Reboots OFFLINE.
|
||||
# Das Script zieht die ganze Kette autonom durch und loggt alles.
|
||||
#
|
||||
# Kette: pre-flight -> flash -> warte down -> warte up(.1.1|.239)
|
||||
# -> (falls .1.1) IP zurück auf .239 [cmd dynamisch entdeckt]
|
||||
# -> VLANs (best-effort) -> save-to-flash -> verify
|
||||
#
|
||||
# Aufruf: ./flash-and-recover.sh preflight # nur Checks, kein Flash
|
||||
# ./flash-and-recover.sh run # echter Flash + Recovery
|
||||
set -u
|
||||
|
||||
SW_PROD=10.40.41.239
|
||||
SW_DEFAULT=192.168.1.1
|
||||
PROD_MASK=255.255.255.0
|
||||
PROD_GW=10.40.41.254
|
||||
ALIAS_IP=192.168.1.2
|
||||
VLANS=10,20,30,40,100
|
||||
IMG="${IMG:-$HOME/bf-switch-flash/all-sg8316m-version_2.2.1_vmlinux.bix}"
|
||||
IMG_SHA=e3f160983e8b17962dc70a52360b7f560c92da8197928d702f5266027a0fc7fc
|
||||
LOG="${LOG:-$HOME/bf-switch-flash/flash-$(date +%Y%m%d-%H%M%S).log}"
|
||||
MODE="${1:-preflight}"
|
||||
|
||||
mkdir -p "$(dirname "$LOG")"
|
||||
log(){ printf '%s %s\n' "$(date '+%H:%M:%S')" "$*" | tee -a "$LOG"; }
|
||||
|
||||
# Liveness: Webserver-Root antwortet (firmware-stabiler als ein bestimmter cmd)
|
||||
http_code(){ curl -s -o /dev/null -w '%{http_code}' --max-time 5 "http://$1/" 2>/dev/null; }
|
||||
up(){ [ "$(http_code "$1")" = "200" ]; }
|
||||
fw_version(){ curl -s --max-time 6 "http://$1/cgi-bin/dispatcher.cgi?cmd=512" \
|
||||
| sed -e 's/<[^>]*>/ /g' | grep -oiE 'Firmware Version[^0-9]*[0-9.]+' | head -1; }
|
||||
|
||||
wait_up(){ _e=$(( $(date +%s) + $2 )); while [ "$(date +%s)" -lt "$_e" ]; do up "$1" && return 0; sleep 4; done; return 1; }
|
||||
wait_down(){ _e=$(( $(date +%s) + $2 )); while [ "$(date +%s)" -lt "$_e" ]; do up "$1" || return 0; sleep 4; done; return 1; }
|
||||
|
||||
# IP zurücksetzen — cmd + Seite dynamisch aus der Live-UI entdecken (firmware-drift-sicher)
|
||||
restore_ip(){
|
||||
_host=$1
|
||||
_menu=$(curl -s --max-time 8 "http://$_host/cgi-bin/dispatcher.cgi?cmd=2")
|
||||
_ipcmd=$(printf '%s' "$_menu" | grep -i 'IP Address' | grep -oE 'cmd=[0-9]+' | head -1 | cut -d= -f2)
|
||||
[ -z "$_ipcmd" ] && _ipcmd=517
|
||||
_form=$(curl -s --max-time 8 "http://$_host/cgi-bin/dispatcher.cgi?cmd=$_ipcmd")
|
||||
_post=$(printf '%s' "$_form" | grep -i 'name="cmd"' | grep -oE 'value="[0-9]+"' | head -1 | grep -oE '[0-9]+')
|
||||
[ -z "$_post" ] && _post=518
|
||||
log "restore_ip: ip-page=$_ipcmd post-cmd=$_post -> set $SW_PROD"
|
||||
curl -s --max-time 10 -X POST "http://$_host/cgi-bin/dispatcher.cgi" \
|
||||
--data "mode=0" --data "ip=$SW_PROD" --data "netmask=$PROD_MASK" \
|
||||
--data "gateway=$PROD_GW" --data "cmd=$_post" >/dev/null 2>&1
|
||||
}
|
||||
add_vlans(){ curl -s --max-time 10 -X POST "http://$1/cgi-bin/dispatcher.cgi" \
|
||||
--data "vlanlist=$VLANS" --data "vlanAction=0" --data "name=" --data "cmd=1284" >/dev/null 2>&1; }
|
||||
save_flash(){ curl -s --max-time 15 "http://$1/cgi-bin/dispatcher.cgi?cmd=4358" >/dev/null 2>&1; }
|
||||
|
||||
# ---------- PRE-FLIGHT ----------
|
||||
log "=== PRE-FLIGHT (mode=$MODE) ==="
|
||||
fail=0
|
||||
if [ -f "$IMG" ]; then
|
||||
h=$(shasum -a 256 "$IMG" 2>/dev/null | awk '{print $1}')
|
||||
if [ "$h" = "$IMG_SHA" ]; then log "OK image sha256"; else log "FAIL image sha256: $h"; fail=1; fi
|
||||
else log "FAIL image missing: $IMG"; fail=1; fi
|
||||
if ifconfig en0 2>/dev/null | grep -q "$ALIAS_IP"; then log "OK recovery-alias $ALIAS_IP on en0";
|
||||
else log "FAIL alias $ALIAS_IP missing -> sudo ifconfig en0 alias $ALIAS_IP 255.255.255.0"; fail=1; fi
|
||||
if up "$SW_PROD"; then log "OK switch up at $SW_PROD (FW: $(fw_version "$SW_PROD"))";
|
||||
else log "FAIL switch not reachable at $SW_PROD"; fail=1; fi
|
||||
if [ "$fail" -ne 0 ]; then log "PRE-FLIGHT FAILED -> abort"; exit 2; fi
|
||||
log "PRE-FLIGHT OK"
|
||||
[ "$MODE" = "preflight" ] && { log "preflight-only -> done (kein Flash)"; exit 0; }
|
||||
|
||||
# ---------- FLASH ----------
|
||||
MARKER="$HOME/bf-switch-flash/.flashed-2.2.1"
|
||||
if [ -f "$MARKER" ] && up "$SW_PROD"; then
|
||||
log "Marker vorhanden + Switch up @ $SW_PROD -> Flash übersprungen (nur reconfig)"; skip=1
|
||||
else skip=0; fi
|
||||
if [ "$skip" -eq 0 ]; then
|
||||
log "=== FLASH: lade Image hoch ($IMG) ==="
|
||||
curl -s --max-time 200 -F "type=0" -F "http_file=@$IMG" -F "cmd=4364" \
|
||||
"http://$SW_PROD/cgi-bin/httpupload.cgi" >>"$LOG" 2>&1
|
||||
log "Upload abgeschlossen, warte auf Reboot (down)..."
|
||||
# Der Reboot selbst ist das verlässliche Flash-Signal (Flash erzwingt Neustart).
|
||||
if wait_down "$SW_PROD" 180; then
|
||||
log "Switch down (Reboot) — Flash hat gegriffen"
|
||||
else
|
||||
log "FAIL kein Reboot binnen 180s — Flash vermutlich nicht angenommen (Upload/Format/Auth?)."
|
||||
log " Switch unverändert @ $SW_PROD, Netz intakt, KEIN Reset. Abbruch."
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------- WARTEN AUF WIEDERKEHR ----------
|
||||
log "=== RECOVERY: warte auf Switch (max 6 min, .1.1 ODER .239) ==="
|
||||
target=""; _e=$(( $(date +%s) + 360 ))
|
||||
while [ "$(date +%s)" -lt "$_e" ]; do
|
||||
if up "$SW_DEFAULT"; then target=$SW_DEFAULT; break; fi
|
||||
if up "$SW_PROD"; then target=$SW_PROD; break; fi
|
||||
sleep 4
|
||||
done
|
||||
if [ -z "$target" ]; then
|
||||
log "FAIL Switch kam binnen 6min nicht auf $SW_DEFAULT noch $SW_PROD zurück."
|
||||
log " -> MANUELLE Recovery nötig (Reset-Knopf 10s, dann erneut)."
|
||||
exit 4
|
||||
fi
|
||||
log "Switch zurück an $target"
|
||||
|
||||
# ---------- IP WIEDERHERSTELLEN ----------
|
||||
if [ "$target" = "$SW_DEFAULT" ]; then
|
||||
log "Switch auf Default $SW_DEFAULT -> stelle $SW_PROD wieder her"
|
||||
restore_ip "$SW_DEFAULT"
|
||||
if wait_up "$SW_PROD" 60; then
|
||||
log "OK Switch wieder auf $SW_PROD"
|
||||
else
|
||||
log "FAIL set-ip griff nicht — FW 2.2.1 erzwingt vermutlich Login (FW1.0 war offen)."
|
||||
log " LAN/Internet laufen TROTZDEM (L2-Forwarding). Nur die Mgmt-IP hängt auf $SW_DEFAULT."
|
||||
log " MANUELL: Browser http://$SW_DEFAULT Login admin/admin -> Network/IP Address"
|
||||
log " -> $SW_PROD Maske $PROD_MASK GW $PROD_GW -> Save to Flash."
|
||||
exit 5
|
||||
fi
|
||||
else
|
||||
log "Switch hat $SW_PROD behalten (Firmware bewahrte IP)"
|
||||
fi
|
||||
|
||||
# ---------- RECONFIG (best-effort, unkritisch — online nachholbar) ----------
|
||||
log "=== reconfig (best-effort) ==="
|
||||
if add_vlans "$SW_PROD"; then log "VLANs $VLANS abgeschickt"; else log "WARN VLAN-Add fehlgeschlagen (online nachholen)"; fi
|
||||
if save_flash "$SW_PROD"; then log "save-to-flash abgeschickt"; else log "WARN save fehlgeschlagen (online nachholen!)"; fi
|
||||
|
||||
# ---------- VERIFY ----------
|
||||
if up "$SW_PROD"; then
|
||||
touch "$HOME/bf-switch-flash/.flashed-2.2.1"
|
||||
log "=== SUCCESS: Switch up @ $SW_PROD (Marker gesetzt) ==="
|
||||
exit 0
|
||||
else
|
||||
log "=== WARN: Switch am Ende nicht bestätigt up ==="
|
||||
exit 6
|
||||
fi
|
||||
15
switch/recovery/switch-recovery-ip.sh
Normal file
15
switch/recovery/switch-recovery-ip.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Recovery-Anker: Zweit-IP 192.168.1.2/24 auf en0, damit der Mac mini den
|
||||
# ALL-SG8316M nach einem Firmware-Flash (Reset auf 192.168.1.1) erreichen kann.
|
||||
# Wird per LaunchDaemon bei jedem Boot ausgeführt (retry bis en0 da ist).
|
||||
IFACE=en0
|
||||
IP=192.168.1.2
|
||||
MASK=255.255.255.0
|
||||
i=0
|
||||
while [ "$i" -lt 10 ]; do
|
||||
if ifconfig "$IFACE" >/dev/null 2>&1; then
|
||||
ifconfig "$IFACE" alias "$IP" "$MASK" 2>/dev/null && exit 0
|
||||
fi
|
||||
i=$((i+1)); sleep 3
|
||||
done
|
||||
exit 1
|
||||
61
switch/sg8316m-cgi-map.md
Normal file
61
switch/sg8316m-cgi-map.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# ALL-SG8316M — dispatcher.cgi API-Map (Recon 2026-06-05)
|
||||
|
||||
> ⚠️ **VERALTET — nur FW 1.0.** Switch ist auf **FW 2.2.1** geflasht; die Web-UI/cmd-Codes hier gelten
|
||||
> NICHT mehr (cmd=2 → 404). Konfiguration jetzt via **Telnet-CLI** → `switch/cli/` (run-cli.exp + .cli).
|
||||
> Dieses Dokument bleibt nur als Historie.
|
||||
|
||||
Switch: **10.40.41.239** · Web-UI: Realtek **`/cgi-bin/dispatcher.cgi?cmd=<N>`** · `Server: Hydra/0.1.8` (FW-Basis 2014).
|
||||
Reine **CGI/Form-POST**-UI (kein JS-SPA) → **vollständig per `curl` skriptbar**. Von diesem Mac direkt erreichbar (~7 ms),
|
||||
ebenso vom Mac mini (10.40.41.167). **Kein SSH** am Switch; **Telnet** existiert als Option (cmd=534), aber curl ist sauberer.
|
||||
|
||||
> ⚠️ Auth-Hinweis: Unauthentifizierte GETs liefern bereits Config-Seiten (bekannte Schwäche dieser Realtek-dispatcher.cgi-Boxen).
|
||||
> Login-Mechanik vor Schreibzugriff verifizieren. **Konsequenz fürs Design:** Mgmt strikt auf vlan10/restricted halten,
|
||||
> EOL-Gerät (2014) nie Richtung WAN exponieren.
|
||||
|
||||
## Befehlscodes (aus Menü cmd=2 extrahiert)
|
||||
|
||||
### 🎯 Für R6-Config gebraucht
|
||||
| cmd | Seite | Zweck |
|
||||
|---|---|---|
|
||||
| **1282** | Create VLAN | VLANs 10/20/30/40/100 anlegen |
|
||||
| **1289** | Interface Settings | Port-Modus (Access/Trunk/Hybrid) + PVID |
|
||||
| **1291** | Port to VLAN | VLAN↔Port-Matrix |
|
||||
| **1293** | Port VLAN Membership | tagged/untagged je Port |
|
||||
| **1297** | Management VLAN | Mgmt-VLAN 1→10 (Cutover) |
|
||||
| **517** | IP Address | Switch-Mgmt-IP (Ziel 10.40.41.2) |
|
||||
| **524** | Account Manager | eigenen User anlegen |
|
||||
| **534/537/539** | Telnet/HTTP/HTTPS | Zugangsdienste |
|
||||
|
||||
### 🔧 Maintenance
|
||||
| cmd | Seite |
|
||||
|---|---|
|
||||
| 4361 | Backup Manager (User: Export defekt → wir scrapen stattdessen, s.u.) |
|
||||
| 4363 | Upgrade Manager (**Firmware**) |
|
||||
| 4358 | Configuration Manager / Save-to-Flash |
|
||||
| 524 | Account Manager |
|
||||
|
||||
### ⛔ NICHT aufrufen (destruktiv/disruptiv)
|
||||
| cmd | Wirkung |
|
||||
|---|---|
|
||||
| 4352 | **Reboot** |
|
||||
| 4354 | **Factory Default / Restore Defaults** |
|
||||
| 4358 | Save to FLASH — nur bewusst am Ende eines Config-Laufs |
|
||||
|
||||
### Weitere (Referenz)
|
||||
Status 512(SysInfo) 3848(Log) · Port 779/774/1031/4619/1814 · Net 517/519/1297 · Time 541/543 ·
|
||||
Switching 768(Port) 2048(Mirror) · LAG 1024/1026/1032/1034/1036 · VoiceVLAN 1536/1538/1543 3328(EEE) ·
|
||||
Multicast 1792 · IGMP 1802/1806/1797/1796/1808 3072(Jumbo) · STP 4096/4098/4100/4102/4108 ·
|
||||
MAC 2311/2309/2304 · Security: Storm 3586/3584 772(Protected) DoS 4864/4866 · Access 534/537/539 ·
|
||||
QoS 2560/2562/2564/2566/2568/2570 Basic 2572/2574 RateLimit 3588/3590/3592 ·
|
||||
LLDP 4608/4610/4617/4614/4621 · SNMP 2816/2818/2821 · Diag 5120/527/530 · Logging 3840/3842/3844 ·
|
||||
Maint 4361/4363/4358/524 4354/4352.
|
||||
|
||||
## „Backup" trotz defektem Export
|
||||
User: Config-Import/Export der FW ist kaputt. **Kein Blocker:** Wir GETten jede Config-Seite per curl in Textdateien
|
||||
(`switch/state-PRE/*.html`) → **git-versionierter, menschenlesbarer Ist-Zustand** statt opaker Binär-Blob. Restore =
|
||||
gezielte CGI-POSTs (nicht Blob-Reupload). Damit ist der Vorgang reproduzierbar + diff-bar.
|
||||
|
||||
## Skript-Plan (statt MCP)
|
||||
`switch/sg8316m.sh` (bash+curl) oder `.py` (requests): login→Session-Cookie → State-Scrape (PRE) →
|
||||
VLANs anlegen (1282) → Interface/Membership (1289/1293) → optional Mgmt-VLAN/IP (1297/517) → Save (4358).
|
||||
Idempotent, dry-run-fähig, im Repo versioniert. Läuft von hier oder vom Mac mini.
|
||||
72
switch/sg8316m.sh
Executable file
72
switch/sg8316m.sh
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
# ⚠️ VERALTET — nur FW 1.0. Switch ist auf FW 2.2.1 geflasht; die dispatcher.cgi-cmd-Codes
|
||||
# unten gelten dort NICHT mehr. Konfig jetzt via Telnet-CLI: switch/cli/ (run-cli.exp + .cli).
|
||||
# Bleibt nur als Historie / für den (unwahrscheinlichen) FW-1.0-Rollback.
|
||||
# ALL-SG8316M (Realtek dispatcher.cgi) driver — curl-based, no MCP needed.
|
||||
# Read ops are safe. WRITE ops change config; SAVE persists to flash.
|
||||
# Creds via ./.secrets (gitignored): SW_HOST, SW_USER, SW_PASS.
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
[ -f "$HERE/.secrets" ] && . "$HERE/.secrets"
|
||||
HOST="${SW_HOST:-10.40.41.239}"
|
||||
BASE="http://$HOST/cgi-bin/dispatcher.cgi"
|
||||
CURL=(curl -sS --max-time 12)
|
||||
|
||||
# --- read ---
|
||||
get() { "${CURL[@]}" "$BASE?cmd=$1"; }
|
||||
|
||||
# Curated config-view + AJAX-data cmd codes (see sg8316m-cgi-map.md)
|
||||
SCRAPE_CMDS="512 517 519 1297 541 543 768 779 1024 1026 1031 \
|
||||
1282 1283 1289 1291 1293 534 537 539 524 \
|
||||
4096 4098 4100 2560 2562 2564 2572 2574 2816 2818 2821 3840 3842 3844"
|
||||
|
||||
scrape() {
|
||||
local out="$HERE/${1:-state-PRE}"; mkdir -p "$out"
|
||||
echo "Scraping $HOST -> $out"
|
||||
for c in $SCRAPE_CMDS; do
|
||||
if "${CURL[@]}" "$BASE?cmd=$c" >"$out/cmd-$c.html" 2>/dev/null; then
|
||||
printf ' cmd=%-5s %6s bytes\n' "$c" "$(wc -c <"$out/cmd-$c.html" | tr -d ' ')"
|
||||
else
|
||||
printf ' cmd=%-5s FAILED\n' "$c"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Pretty-print one page as text
|
||||
view() { get "$1" | sed -e 's/<[^>]*>/ /g' | tr -s ' \t\r\n' ' ' | sed 's/ / /g'; echo; }
|
||||
|
||||
# --- write (use deliberately, then `save`) ---
|
||||
post() { "${CURL[@]}" -X POST "$BASE" "$@"; }
|
||||
|
||||
add_vlans() { post --data-urlencode "vlanlist=$1" --data "vlanAction=0" --data-urlencode "name=${2:-}" --data "cmd=1284"; }
|
||||
del_vlans() { post --data-urlencode "vlanlist=$1" --data "vlanAction=1" --data "cmd=1284"; }
|
||||
# set_ip <ip> [netmask] [gateway] — RECOVERY: re-point mgmt IP (e.g. after flash reset to 192.168.1.1)
|
||||
set_ip() { post --data "mode=0" --data "ip=$1" --data "netmask=${2:-255.255.255.0}" --data "gateway=${3:-10.40.41.254}" --data "cmd=518"; }
|
||||
save_flash() { echo ">> SAVE to FLASH (cmd=4358)"; get 4358 >/dev/null; }
|
||||
|
||||
usage() { cat <<USAGE
|
||||
usage: $0 <cmd>
|
||||
scrape [dir] dump config pages to switch/<dir> (default state-PRE) [READ]
|
||||
get <N> raw HTML of cmd=N [READ]
|
||||
view <N> cmd=N as plain text [READ]
|
||||
add-vlans <list> [prefix] e.g. add-vlans 10,20,30,40,100 [WRITE]
|
||||
del-vlans <list> [WRITE]
|
||||
set-ip <ip> [mask] [gw] RECOVERY: re-point mgmt IP [WRITE]
|
||||
save persist running config to flash [WRITE]
|
||||
|
||||
Recovery after flash (switch reset to 192.168.1.1):
|
||||
SW_HOST=192.168.1.1 SW_USER=admin SW_PASS=admin $0 set-ip 10.40.41.239
|
||||
USAGE
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
scrape) scrape "${2:-state-PRE}" ;;
|
||||
get) get "$2" ;;
|
||||
view) view "$2" ;;
|
||||
add-vlans) add_vlans "$2" "${3:-}" ;;
|
||||
del-vlans) del_vlans "$2" ;;
|
||||
set-ip) set_ip "$2" "${3:-255.255.255.0}" "${4:-10.40.41.254}" ;;
|
||||
save) save_flash ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user