Die Auswertung liest jetzt beide Geraete und stellt sie je Raum untereinander: REFERENZ (iPhone, frei) was du an dieser Stelle wirklich hast SONDE (S22, Gegen-AP) was die Rueckfallebene noch leisten koennte Damit faellt der Terrassen-Vergleich beim naechsten Lauf von selbst raus, und die Lesart wird eindeutig: gute Referenz + schlechte Sonde = alles haengt an EINEM AP; beide schlecht = echtes Loch ohne Rueckfallebene (der Kuechenfall). Rueckwaertskompatibel: Laeufe ohne walk-ping-iphone.csv/beide-telefone.csv laufen einspaltig weiter und liefern fuer den Lauf vom 22.8. Ziffer fuer Ziffer dieselben Zahlen wie vorher. Das Geraet heisst dort "Geraet" -- welches es war, steht in den Dateien nicht, also wird es auch nicht behauptet. Drei Fehler, die der Abnahmetest zutage foerderte und die alle den naechsten Rundgang gekostet haetten: 1. Die Gegen-AP-Automatik war nach dem Start AUS. Wer den Klick vergisst, geht die ganze Runde mit beiden Telefonen auf DEMSELBEN AP -- im Test genau so passiert. tp25-runde.sh schaltet sie jetzt scharf; /auto nimmt dafuer ?an=1 (ein Toggle waere falsch: bei schon laufender Konsole haette der Start sie ausgeschaltet). 2. "Funk da, aber keine einzige Ping-Antwort" erschien als "—", also wie eine Datenluecke. Beim Test lag das iPhone gesperrt auf dem Tisch: angemeldet mit -47 dBm und trotzdem stumm. Wer das als Luecke liest, sucht danach ein Funkloch, das es nicht gibt. Jetzt: "keine Antwort" + "⚠️ Display gesperrt?". 3. Der Aufraeumer meldete "AP-Pin geloest", und danach standen die Regeln trotzdem am Core. Wettlauf: er loeste den Pin, waehrend die Konsole noch lief, und deren Automatik setzte ihn binnen zwei Sekunden wieder. Das Telefon waere nach JEDER Runde gepinnt geblieben. Jetzt erst Konsole toeten, dann Pin loesen. Zuletzt: tp25-pin-s22.sh laeuft auf sshpass -e. Damit steht das Router-Passwort in keiner Kommandozeile mehr -- `grep -rn "sshpass -p" docs/ nautobot/` findet nur noch die Erwaehnung in teilprojekte.md. Die Rotation kann jetzt kommen. Abnahme (mehrere echte Laeufe): Automatik meldet EIN, beide Telefone stehen auf verschiedenen APs, beide werden gepingt, ein Klick auf Stopp beendet alles, Pin danach "off", kein Prozess uebrig. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
124 lines
6.1 KiB
Bash
Executable File
124 lines
6.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# TP25 — einen Client per access-list auf EINEN AP festnageln.
|
|
#
|
|
# Wozu: die Gehweg-Messungen von 08-20/21 zeigen den Sticky-Client (Fund B) und das
|
|
# Band-Ping-Pong (Fund C) — aber sie zeigen NICHT, wie gut ein einzelner AP eine Wohnung
|
|
# allein ausleuchtet, weil der Client waehrend des Wegs wechselt. Wer die Abdeckung von
|
|
# ap1 und ap2 vergleichen will, muss den Wechsel vorher ausschliessen.
|
|
#
|
|
# Mechanik: am MANAGER (crs326-core) wird der Client auf den Radios des jeweils ANDEREN
|
|
# AP mit action=reject abgewiesen. Uebrig bleibt genau ein AP. Die Baender dieses AP
|
|
# bleiben bewusst BEIDE offen — gepinnt wird der Standort, nicht das Band.
|
|
#
|
|
# bash docs/tp25-pin-s22.sh ap2 # nur ap2 erlaubt (ap1 abgewiesen)
|
|
# bash docs/tp25-pin-s22.sh ap1 # nur ap1 erlaubt (ap2 abgewiesen)
|
|
# bash docs/tp25-pin-s22.sh off # Pin loesen, Normalbetrieb
|
|
# bash docs/tp25-pin-s22.sh status # Regeln + aktuelle Anmeldung zeigen
|
|
# bash docs/tp25-pin-s22.sh map # cap-wifiN -> apX/Band, LIVE vom Manager
|
|
# bash docs/tp25-pin-s22.sh which # auf welchem AP der Pin gerade steht (ap1|ap2|off)
|
|
#
|
|
# 🔴 Die access-list steht unter KEINER ComplianceRule (Stand 2026-08-22: es gibt
|
|
# wifi-configuration/-datapath/-security/-steering/-provisioning/-channel/-cap/-capsman,
|
|
# aber keine fuer access-list). Dieser Change erzeugt deshalb KEINEN Drift und wird von
|
|
# Nautobot auch nicht bemerkt. Genau darum traegt jede Regel den Kommentar TP25-PIN-S22
|
|
# und das Skript raeumt vor jedem Setzen auf: es gibt keine zweite Instanz, die das tut.
|
|
# Wenn Fund E (signal-range-Boden) dauerhaft kommt, gehoert diese Luecke geschlossen.
|
|
#
|
|
# ⚠️ Android randomisiert die MAC je SSID. Die hier gepinnte Adresse gilt fuer
|
|
# dirtyvader-main; wechselt das Telefon die SSID oder wuerfelt neu, greift der Pin
|
|
# still nicht mehr. Kontrolle ist immer `status`, nie die Annahme.
|
|
|
|
set -uo pipefail
|
|
|
|
MAC="${TP25_PIN_MAC:-2A:0D:B0:5D:AD:A7}"
|
|
TAG="TP25-PIN-S22"
|
|
ROUTER_IP="${TP25_MANAGER_IP:-10.40.99.1}"
|
|
|
|
# 🔴 Die cap-wifiN-Nummern werden vom Manager DYNAMISCH vergeben, in der Reihenfolge, in der
|
|
# sich die CAPs anmelden. Ein fest verdrahtetes Mapping ist damit nur so lange richtig, bis
|
|
# ein AP einmal neu bootet oder umgesteckt wird -- und es faellt still falsch aus, weil die
|
|
# Zahlen weiter existieren. (Genau so standen sie am 2026-08-22 in docs/tp6-marker/server.py
|
|
# und docs/tp25-gehweg-auswertung.py verkehrt herum: Baender richtig, ap1/ap2 vertauscht.)
|
|
# Deshalb wird hier NICHTS gecacht -- die Zuordnung kommt bei jedem Aufruf vom Geraet.
|
|
|
|
ZIEL="${1:-status}"
|
|
|
|
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: mit -p steht das Router-Passwort in der Kommandozeile und damit
|
|
# in `ps` und in jedem Prozess-Trace. Am 2026-08-22 ist es genau so im Klartext in einen
|
|
# Sitzungsmitschnitt geraten. Die sed-Maskierung der Ausgabe bleibt als zweite Schicht.
|
|
ros() {
|
|
SSHPASS="$PW" sshpass -e ssh -o StrictHostKeyChecking=no -o ConnectTimeout=8 \
|
|
"admin@${ROUTER_IP}" "$1" 2>&1 | sed "s/${PW//\//\\/}/***/g"
|
|
}
|
|
|
|
# cap-wifiN -> "apX Band" -- live, ohne Cache. Ausgabe je Zeile: cap-wifi3=ap1/5GHz
|
|
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)}' \
|
|
| tr -d '\r' | grep '^cap-wifi[0-9]*='
|
|
}
|
|
|
|
# Auf welchem AP steht der Pin? Ergibt sich aus den Regeln: abgewiesen wird der ANDERE AP.
|
|
welcher() {
|
|
local m; m="$(karte)"
|
|
local regeln; regeln="$(ros "/interface wifi access-list print terse where comment=\"$TAG\"")"
|
|
[[ -z "${regeln//[[:space:]]/}" ]] && { echo off; return; }
|
|
local blockiert; blockiert="$(echo "$regeln" | grep -o 'interface=cap-wifi[0-9]*' | cut -d= -f2)"
|
|
local aps_blockiert; aps_blockiert="$(for i in $blockiert; do echo "$m" | grep "^$i=" | cut -d= -f2 | cut -d/ -f1; done | sort -u)"
|
|
# Uebrig bleibt der AP, der NICHT blockiert ist.
|
|
for ap in $(echo "$m" | cut -d= -f2 | cut -d/ -f1 | sort -u); do
|
|
echo "$aps_blockiert" | grep -qx "$ap" || { echo "$ap"; return; }
|
|
done
|
|
echo off
|
|
}
|
|
|
|
# Die Interfaces EINES AP -- live ermittelt, nicht geraten.
|
|
ifaces_von() {
|
|
karte | grep "=$1/" | cut -d= -f1
|
|
}
|
|
|
|
aufraeumen() {
|
|
ros "/interface wifi access-list remove [find where comment=\"$TAG\"]" >/dev/null
|
|
}
|
|
|
|
# Der Reject greift erst bei der NAECHSTEN Anmeldung. Ohne Kick bleibt das Telefon
|
|
# u.U. minutenlang auf dem verbotenen AP haengen -- und der Rundgang misst dann nichts.
|
|
kick() {
|
|
ros "/interface wifi registration-table remove [find where mac-address=\"$MAC\"]" >/dev/null
|
|
}
|
|
|
|
zeigen() {
|
|
echo "--- Regeln ($TAG) ---"
|
|
local r; r="$(ros "/interface wifi access-list print terse where comment=\"$TAG\"")"
|
|
if [[ -z "${r//[[:space:]]/}" ]]; then echo " (keine -- Pin ist AUS)"; else echo "$r" | sed 's/^/ /'; fi
|
|
echo "--- Anmeldung $MAC ---"
|
|
local a; a="$(ros "/interface wifi registration-table print terse where mac-address=\"$MAC\"")"
|
|
if [[ -z "${a//[[:space:]]/}" ]]; then echo " (nicht angemeldet)"; else echo "$a" | sed 's/^/ /'; fi
|
|
}
|
|
|
|
case "$ZIEL" in
|
|
ap1|ap2)
|
|
ANDERER="ap1"; [[ "$ZIEL" == "ap1" ]] && ANDERER="ap2"
|
|
SPERREN="$(ifaces_von "$ANDERER" | tr '\n' ' ')"
|
|
if [[ -z "${SPERREN//[[:space:]]/}" ]]; then
|
|
echo "Keine Interfaces fuer $ANDERER gefunden -- haengt der AP am Manager? Abbruch." >&2; exit 1
|
|
fi
|
|
aufraeumen
|
|
for i in $SPERREN; do
|
|
ros "/interface wifi access-list add mac-address=$MAC interface=$i action=reject comment=\"$TAG\"" >/dev/null
|
|
done
|
|
echo "S22 -> nur $ZIEL ($ANDERER abgewiesen auf: $SPERREN)"; kick ;;
|
|
off)
|
|
aufraeumen; echo "Pin geloest -- S22 darf wieder ueberall."; kick ;;
|
|
status) ;;
|
|
map) karte; exit 0 ;;
|
|
which) welcher; exit 0 ;;
|
|
*) echo "Aufruf: $0 {ap1|ap2|off|status|map|which}" >&2; exit 2 ;;
|
|
esac
|
|
|
|
[[ "$ZIEL" == "status" ]] || sleep 6
|
|
zeigen
|