#!/usr/bin/env bash # # TP6 — Core-Sampler (read-only) # # Haengt EINE persistente SSH-Sitzung an crs326-core und laesst dort eine Console-Schleife # laufen, die im festen Takt eine CSV-Zeile ausgibt: Core-CPU, WAN-Rate auf vlan100 und # — optional — die Registration-Table-Werte EINES WLAN-Clients. # # 🔴 Ausschliesslich Lesezugriffe (get / find / monitor-traffic once). Kein Write, kein # /system script, kein /system logging. Aendert nichts am Netz. # # 🔴 Unter CAPsMAN fuehrt der MANAGER die Registration-Table — deshalb wird der CORE # abgefragt und nicht ap1/ap2, wo die Tabelle leer waere. # # Aufruf: # bash docs/tp6-monitor-core.sh --out /pfad/sampler.csv # nur CPU/WAN # bash docs/tp6-monitor-core.sh --out /pfad/sampler.csv --mac F2:62:4C:E1:AF:09 # # Beenden: Ctrl-C (oder kill auf die PID). set -uo pipefail MAC="" INTERVAL=2 OUT="" ROUTER_IP="10.40.99.1" while [[ $# -gt 0 ]]; do case "$1" in --mac) MAC="${2:-}"; shift 2 ;; --interval) INTERVAL="${2:-2}"; shift 2 ;; --out) OUT="${2:-}"; shift 2 ;; --ip) ROUTER_IP="${2:-}"; shift 2 ;; *) echo "unbekanntes Argument: $1" >&2; exit 2 ;; esac done [[ -n "$OUT" ]] || { echo "--out fehlt" >&2; exit 2; } # Passwort aus dem Credential-Store. Wird NIE ausgegeben. 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; } # RouterOS-Schleife. Platzhalter werden unten ersetzt (RouterOS nutzt $ selbst, daher kein # Shell-Interpolieren im Schleifenkoerper). read -r -d '' ROS <<'ROS_EOF' :local m "__MAC__"; :while (true) do={ :local cpu [/system resource get cpu-load]; :local w [/interface monitor-traffic vlan100 once as-value]; :local line ([/system clock get time] . "," . $cpu . "," . ($w->"rx-bits-per-second") . "," . ($w->"tx-bits-per-second")); :if ([:len $m] > 0) do={ :local id [/interface/wifi/registration-table find where mac-address=$m]; :if ([:len $id] = 0) do={ :set line ($line . ",absent,,,,,,"); } else={ :local r [/interface/wifi/registration-table get [:pick $id 0]]; :set line ($line . "," . ($r->"interface") . "," . ($r->"signal") . "," . ($r->"tx-rate") . "," . ($r->"rx-rate") . "," . ($r->"tx-bits-per-second") . "," . ($r->"rx-bits-per-second") . "," . ($r->"uptime") . "," . ($r->"last-activity")); }; }; :put $line; :delay __DELAY__s; } ROS_EOF ROS="${ROS//__MAC__/$MAC}" ROS="${ROS//__DELAY__/$INTERVAL}" # 🔴 Die RouterOS-Console parst eine per SSH uebergebene Mehrzeilen-Eingabe ZEILENWEISE # ("expected closing brace"). Das Skript muss deshalb als EINE Zeile ankommen — # und jeder do={}-Block braucht dann ein abschliessendes ";", sonst kommt # "expected end of command". ROS="$(printf '%s' "$ROS" | tr '\n' ' ')" echo "ts_epoch,ts_local,ros_time,cpu,wan_rx_bps,wan_tx_bps,sta_iface,sta_signal,sta_tx_rate,sta_rx_rate,sta_tx_bps,sta_rx_bps,sta_uptime,sta_last_activity" > "$OUT" echo "Sampler laeuft -> $OUT (Takt ${INTERVAL}s${MAC:+, Client $MAC})" # Lokaler Zeitstempel beim Eintreffen der Zeile. Bewusst kein awk: das BSD-awk auf macOS # kennt systime()/strftime() nicht (das ist gawk). # # 🔴 Mit Reconnect-Schleife: die SSH-Sitzung ist am 2026-08-21 mitten in einer Gehweg-Messung # weggebrochen ("Can't assign requested address"), und die Funkdaten endeten 2,5 Minuten vor # dem Ping-Mitschnitt — ausgerechnet im interessanten Teil. Ein Sampler, der still stirbt, # ist schlimmer als keiner. while true; do # 🔴 -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 so im Klartext in einen Mitschnitt # geraten. Mit -e liegt es nur in der Umgebung dieses Kindprozesses. SSHPASS="$PW" sshpass -e ssh -o StrictHostKeyChecking=no -o ConnectTimeout=8 \ -o ServerAliveInterval=15 -o ServerAliveCountMax=3 "admin@${ROUTER_IP}" "$ROS" \ 2>>"${OUT%.csv}.stderr.log" \ | while IFS= read -r line; do printf '%s,%s,%s\n' "$(date +%s)" "$(date +%H:%M:%S)" "$line" >> "$OUT" done printf '%s,%s,RECONNECT\n' "$(date +%s)" "$(date +%H:%M:%S)" >> "$OUT" echo "$(date +%H:%M:%S) Verbindung weg -- neuer Versuch in 2 s" >> "${OUT%.csv}.stderr.log" sleep 2 done