diff --git a/docs/tp25-pin-multi.sh b/docs/tp25-pin-multi.sh new file mode 100755 index 0000000..7d14742 --- /dev/null +++ b/docs/tp25-pin-multi.sh @@ -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- -- 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