LabCodeHub öffentliche Ansicht
Anmelden
Küpper / netcheck öffentlich
Branch: main ▾
Klonen
Verlauf
R Rüdiger Küpper fix: readme and netcheck.sh
14d3ef98 vor 1 Monat
.gitignore erster Commit vor 1 Monat
cloud.tytik.netcheck.plist erster Commit vor 1 Monat
netcheck.conf.example erster Commit vor 1 Monat
netcheck.service erster Commit vor 1 Monat
netcheck.sh fix: readme and netcheck.sh vor 1 Monat
netcheck.timer erster Commit vor 1 Monat
README.md fix: readme and netcheck.sh vor 1 Monat
README.md

netcheck — Langzeit-Monitoring der IPv4-/IPv6-Erreichbarkeit

Kleines, abhängigkeitsarmes Shell-Script, das über Tage oder Wochen protokolliert,
wann Verbindungsprobleme auftreten und welcher Art sie sind. Gedacht für
Fälle, in denen ein Kunde "immer mal wieder" Störungen meldet, sich aber niemand
zum Zeitpunkt des Fehlers am Rechner befindet.

Pro Durchlauf wird für jedes Ziel und jede Protokollfamilie gemessen:

  • curl-Timing — DNS-Auflösung, TCP-Connect, TLS-Handshake, Time-to-first-byte,

Gesamtdauer, HTTP-Status und die tatsächlich kontaktierte IP

  • mtr-Pfadmessung — Paketverlust und Latenz pro Hop, im TCP-Modus auf Port 443

Ergebnis ist eine CSV-Datei mit einer Zeile je Ziel und Protokoll sowie —
ausschließlich bei auffälligen Läufen — ein Rohlog mit der vollständigen
mtr-Ausgabe und einer längeren Nachmessung.


Warum diese Kombination

Die beiden Messungen beantworten unterschiedliche Fragen, und erst zusammen
grenzen sie eine Störung ein:

BeobachtungInterpretation
curl schlägt fehl, mtr erreicht das Ziel sauberNetzpfad in Ordnung, Problem liegt auf Anwendungsebene — Webserver, TLS, WAF, Rate-Limit
curl und mtr scheitern gemeinsamNetzproblem, mtr zeigt im Rohlog den Hop, ab dem es abreißt
nur IPv6 betroffen, IPv4 läuftDual-Stack-Problem — fehlende Route, kaputte Router-Advertisements, PMTU
hohe tls_ms bei normalem connect_msTLS-Handshake ist langsam, nicht die Leitung
hohe ttfb_ms bei normalem tls_msServer denkt lange nach, Netz ist unschuldig
Verlust auf einem Zwischenhop, Ziel aber 0 %Meist harmlos: der Router priorisiert nur seine eigenen ICMP-Antworten herunter

Die letzte Zeile ist der häufigste Fehlschluss beim Lesen von mtr-Ausgaben.
Relevant ist Verlust nur, wenn er sich ab einem Hop bis zum Ziel durchzieht.


Installation

Voraussetzungen

  • bash, curl, awk, find — auf macOS und jedem Linux vorhanden
  • mtr — muss nachinstalliert werden:
  • macOS: brew install mtr
  • Debian/Ubuntu: sudo apt install mtr-tiny
  • RHEL/Rocky: sudo dnf install mtr

Ohne mtr läuft das Script weiter, zeichnet dann aber nur die curl-Messungen auf.

Dateien ablegen

sudo mkdir -p /usr/local/netcheck
sudo cp netcheck.sh /usr/local/netcheck/
sudo chmod +x /usr/local/netcheck/netcheck.sh
sudo cp netcheck.conf.example /usr/local/netcheck/netcheck.conf
sudo vi /usr/local/netcheck/netcheck.conf

Rechte

mtr benötigt Raw Sockets und damit Root-Rechte. Drei Varianten, absteigend
nach Sauberkeit:

  1. Als root per Scheduler starten (empfohlen, siehe unten) — dann ist nichts

weiter zu tun.

  1. Passwortloses sudo nur für mtr. Das Script erkennt das automatisch und

ruft sudo -n mtr auf. Regel anlegen mit sudo visudo -f /etc/sudoers.d/netcheck:

   deinbenutzer ALL=(root) NOPASSWD: /opt/homebrew/bin/mtr

Pfad vorher mit command -v mtr prüfen — unter Linux meist /usr/bin/mtr.

  1. Ohne Root — dann bleiben die mtr-Spalten leer und es werden nur

curl-Messungen aufgezeichnet. Für eine erste Eingrenzung reicht das oft.

Prüfen

/usr/local/netcheck/netcheck.sh selftest

Der Selbsttest meldet fehlende Werkzeuge, die Rechtelage und macht einen
Testabruf pro Ziel und Protokollfamilie.


Betrieb

BefehlWirkung
netcheck.sh onceeinmaliger Lauf mit Ausgabe im Terminal
netcheck.sh runeinmaliger Lauf, still — für cron, launchd, systemd
netcheck.sh daemonEndlosschleife im Abstand von INTERVAL
netcheck.sh stopbeendet einen laufenden daemon sauber
netcheck.sh summaryAuswertung der gesammelten Daten
netcheck.sh selftestprüft Voraussetzungen, Rechte und Erreichbarkeit

Einzelner Lauf mit Ausgabe

sudo /usr/local/netcheck/netcheck.sh once

Dauerbetrieb im Vordergrund

Praktisch, um über Nacht in einer Terminal-Session mitlaufen zu lassen:

sudo /usr/local/netcheck/netcheck.sh daemon

Sauber beenden

Ctrl+C im Terminal, oder aus einer zweiten Shell:

sudo /usr/local/netcheck/netcheck.sh stop

Beides läuft über denselben Weg: das Script merkt sich den Stopp-Wunsch,
beendet die gerade laufende Messung und verwirft sie ersatzlos — eine
abgebrochene Messung landet nicht in der CSV. Das ist der entscheidende Punkt,
denn eine mitten im Lauf abgeschossene curl- oder mtr-Messung sieht in den Daten
exakt wie ein echter Ausfall aus und würde die Auswertung verfälschen. Im
Betriebslog steht stattdessen eine SKIP-Zeile.

Ein zweites Ctrl+C erzwingt den sofortigen Abbruch. Dann kann eine unvollständige
Messung in den Rohlogs zurückbleiben — die CSV bleibt aber auch in diesem Fall
sauber, weil die Zeile erst nach vollständiger Messung geschrieben wird.

netcheck.sh stop findet die laufende Instanz über die Sperrdatei, wartet bis
zu 60 Sekunden auf ein sauberes Ende und greift erst danach härter durch. Eine
verwaiste Sperre nach einem Absturz räumt es ebenfalls auf.

Falls doch einmal etwas hängt — etwa nach einem kill -9 —, hilft:

sudo pkill -9 -f 'netcheck.sh daemon'
sudo pkill -9 mtr
sudo rm -rf /usr/local/netcheck/data/.lock

Verfälschte Zeilen nachträglich entfernen

Wurden durch einen harten Abbruch doch Scheinausfälle aufgezeichnet, lassen sie
sich gezielt löschen. Von einem Signal abgeschossene Messungen haben einen
curl_exit ab 128 (meist 130 für SIGINT):

cd /usr/local/netcheck/data/csv
for f in netcheck-*.csv; do
  awk -F, 'NR==1 || $8+0 < 128' "$f" > "$f.tmp" && mv "$f.tmp" "$f"
done

Alternativ alle Zeilen eines bestimmten Laufs anhand der runid (Spalte 3, im
Format JJJJMMTT-HHMMSS) entfernen:

awk -F, '$3 != "20260902-143000"' netcheck-2026-09.csv > tmp && mv tmp netcheck-2026-09.csv

Vorher mit grep prüfen, was die Filter treffen würden — die CSV ist die
Beweislage, versehentlich gelöschte echte Ausfälle sind nicht rekonstruierbar.

Dauerbetrieb per Scheduler

macOS (launchd):

sudo cp cloud.tytik.netcheck.plist /Library/LaunchDaemons/
sudo chown root:wheel /Library/LaunchDaemons/cloud.tytik.netcheck.plist
sudo chmod 644 /Library/LaunchDaemons/cloud.tytik.netcheck.plist
sudo launchctl load -w /Library/LaunchDaemons/cloud.tytik.netcheck.plist

Vorher den Pfad in ProgramArguments und das Intervall in StartInterval
kontrollieren. Beenden mit launchctl unload -w ….

Linux (systemd):

sudo cp netcheck.service netcheck.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now netcheck.timer
systemctl list-timers netcheck.timer

Linux (cron), falls systemd nicht gewünscht ist:

*/5 * * * * root /usr/local/netcheck/netcheck.sh run

Überlappende Läufe sind ausgeschlossen: das Script setzt eine Sperre und
überspringt einen Start, solange der vorherige Lauf noch läuft.


Konfiguration

Alle Werte stehen in netcheck.conf neben dem Script (Vorlage:
netcheck.conf.example). Die wichtigsten:

VariableDefaultBedeutung
TARGETStytik.cloudZiele, durch Leerzeichen getrennt, ohne https://
FAMILIES4 6zu prüfende Protokollfamilien
OUTDIR./dataAblage für CSV, Rohlogs und Logfile
INTERVAL300Abstand im daemon-Modus in Sekunden
MTR_CYCLES10Pings pro Hop im Normalfall
MTR_ANOMALY_CYCLES30Pings pro Hop bei der Nachmessung
LOSS_WARN5Paketverlust zum Ziel in %, ab dem ein Lauf auffällig ist
RTT_WARN150mittlere Latenz zum Ziel in ms
TOTAL_WARN3000curl-Gesamtzeit in ms
SNAPSHOT_ON_ANOMALY0bei Auffälligkeit zusätzlich den lokalen Netzzustand mitschreiben
RAW_RETENTION_DAYS30Rohlogs älter als N Tage löschen, 0 = nie

Empfehlung zur Zielauswahl: neben dem eigentlichen Kundenziel ein bis zwei
stabile Referenzziele aufnehmen, etwa one.one.one.one und eine große deutsche
Site. Fällt nur das Kundenziel aus, liegt es am Ziel; fallen alle gleichzeitig
aus, liegt es an der Leitung des Kunden. Diese Unterscheidung erspart die
längsten Diskussionen.

SNAPSHOT_ON_ANOMALY=1 lohnt sich, wenn ein Problem am Client oder am
Kundenrouter vermutet wird. Das Script schreibt dann bei jeder Auffälligkeit
Default-Routen, Router-Advertisements und Interface-Adressen mit — genau die
Angaben, an denen etwa eine verschwundene IPv6-Default-Route sofort sichtbar wird.


Auswertung

/usr/local/netcheck/netcheck.sh summary          # alle vorhandenen Monate
/usr/local/netcheck/netcheck.sh summary 2026-09  # nur September 2026

Ausgabe: Messzeitraum, je Ziel und Protokoll die Zahl der Läufe, Fehler und
Auffälligkeiten samt Durchschnitts- und Maximalwerten, die häufigsten Ursachen
sowie eine Verteilung der Auffälligkeiten nach Tag und nach Tageszeit. Die
Tageszeit-Verteilung ist der schnellste Weg zu einem Muster — Häufungen zur
vollen Stunde deuten auf Backups oder Cronjobs, abendliche Häufungen auf
Überlast im Zugangsnetz, gleichmäßige Verteilung eher auf ein Hardware- oder
Routingproblem.

Rohdaten

data/csv/netcheck-YYYY-MM.csv — eine Zeile je Ziel und Protokoll, direkt in
Excel, LibreOffice oder Grafana einlesbar. Spalten:

SpalteBedeutung
ts, epoch, runidZeitstempel des Laufs
target, familyZiel und Protokollfamilie (4 oder 6)
resolved_iptatsächlich kontaktierte IP — verrät CDN-Wechsel
curl_ok, curl_exit, http_codeErfolg, curl-Exitcode, HTTP-Status
dns_ms, connect_ms, tls_ms, ttfb_ms, total_mscurl-Timing, kumulativ
mtr_ok, mtr_loss_pct, mtr_avg_ms, mtr_worst_msMesswerte am Ziel-Hop
mtr_max_hop_losshöchster Verlust auf irgendeinem Hop
mtr_hops, dest_reachedHop-Anzahl, ob das Ziel geantwortet hat
anomaly, reasonBewertung des Laufs und Klartextbegründung
rawfilePfad zum Rohlog, relativ zu data/raw/

Die curl-Zeiten sind kumulativ: tls_ms enthält connect_ms, dieses enthält
dns_ms. Die Dauer des TLS-Handshakes allein ist also tls_ms − connect_ms.

data/raw/YYYY-MM-DD/… — Rohlogs auffälliger Läufe mit vollständiger
mtr-Ausgabe, Kurzlauf und Nachmessung.

data/netcheck.log — Betriebsprotokoll mit einer Zeile je Auffälligkeit.

Schnelle Handgriffe

# Alle Ausfälle chronologisch
awk -F, '$7==0 {print $1, $4, "IPv"$5, $23}' data/csv/*.csv

# Nur IPv6-Probleme
awk -F, '$5==6 && $22==1 {print $1, $23}' data/csv/*.csv

# Latenzverlauf eines Ziels für ein Diagramm
awk -F, '$4=="tytik.cloud" && $5==4 && $15==1 {print $1","$17}' data/csv/*.csv

Wartung

Rohlogs werden nach RAW_RETENTION_DAYS automatisch gelöscht, CSV-Dateien
bleiben liegen — sie sind klein (rund 200 Byte pro Messung, bei zwei Zielen im
Dual-Stack und 5-Minuten-Takt etwa 6 MB im Monat) und bilden die eigentliche
Beweislage gegenüber dem Provider.

Belastung: ein Lauf erzeugt pro Ziel und Familie einen HTTPS-HEAD-Request und
MTR_CYCLES Pakete je Hop. Bei den Defaults sind das wenige Kilobyte alle fünf
Minuten — unbedenklich auch auf einer schwachen Leitung.


Grenzen

Das Script misst vom Standort aus, an dem es läuft. Meldet der Kunde Probleme,
die hier nicht auftauchen, liegt das Problem entweder beim Kunden selbst oder
tritt nur unter Last auf. In dem Fall gehört eine zweite Instanz auf einen
Rechner im Netz des Kunden — die CSV-Dateien beider Instanzen lassen sich über
die Zeitstempel direkt nebeneinanderlegen.

Ebenfalls nicht abgedeckt: Durchsatzmessungen, DNS-Vergleich zwischen mehreren
Resolvern und die Analyse einzelner TCP-Verbindungen. Lässt sich alles ergänzen,
war für diesen Zweck aber bewusst nicht Teil des Umfangs.