#!/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