#!/usr/bin/env bash set -euo pipefail # Testet ein Interface mit curl gegen mehrere HTTP/HTTPS-Ziele. # Online, sobald mindestens EIN Ziel funktioniert. # Offline erst, wenn ALLE Ziele fehlschlagen. # Erst der zweite Offline-Fall in Folge erzeugt Meldung + ggf. Aktion. # # Usage: # check_inet_iface_curl.sh [--service NAME | --reboot] [--state-dir DIR] # [--max-time SEC] [-h|--help] IFACE="${1:-}" shift || true # Ziele - echte TCP/HTTPS-Tests TARGETS=( "oopen.de" "1.1.1.1" "8.8.8.8" "www.debian.org" ) PING_BIN="$(command -v ping)" DATE_BIN="$(command -v date)" TIMEOUT_BIN="$(command -v timeout)" STATE_DIR="/run/check_inet" MAX_TIME=8 SERVICE="" DO_REBOOT=0 # terminal detection IS_TTY=0 if [[ -t 1 || -t 2 ]]; then IS_TTY=1; fi # colors (TTY only) if [[ $IS_TTY -eq 1 ]]; then RED=$'\e[31m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m'; BOLD=$'\e[1m'; RESET=$'\e[0m' else RED=""; GREEN=""; YELLOW=""; BOLD=""; RESET="" fi usage() { cat <<'USAGE' check_inet_iface_curl.sh - prüft Konnektivität per curl über ein bestimmtes Interface. Usage: check_inet_iface_curl.sh [--restart-service NAME | --reboot] [--state-dir DIR] [--max-time SEC] [-h|--help] Optionen: --restart-service NAME systemd-Service bei 2x OFFLINE in Folge neu starten --reboot bei 2x OFFLINE in Folge System rebooten --state-dir DIR State-Verzeichnis (Default: /run/check_inet) --max-time SEC curl Timeout pro Ziel (Default: 8) -h, --help Hilfe Verhalten: - Im Terminal: grün "OK" bei Erfolg, rot "FAILED" bei 2x OFFLINE + Details. - Als Cron (kein TTY): bei Erfolg keine Ausgabe; bei 2x OFFLINE Meldung auf stderr (damit Cron eine Mail erzeugen kann). Exit-Codes: 0 = online / OK (oder 1. Offline nur gemerkt) 1 = 2x offline in Folge (Fehler + ggf. Aktion) 3 = Aktion fehlgeschlagen USAGE } clean_up() { # Perform program exit housekeeping blank_line exit $1 } log_info() { if [[ $IS_TTY -eq 1 ]] ; then echo -e "$*"; fi } log_err() { echo -e "$*" >&2; } die() { log_err "${RED}${BOLD}ERROR:${RESET} $*"; exit 64; } blank_line() { if [[ $IS_TTY -eq 1 ]] ; then echo "" fi } # ----------------------------- # args # ----------------------------- while [[ $# -gt 0 ]]; do case "$1" in --restart-service) [[ $# -ge 2 ]] || die "--restart-service braucht ein Argument" SERVICE="$2" shift 2 ;; --reboot) DO_REBOOT=1 shift ;; --state-dir) [[ $# -ge 2 ]] || die "--state-dir braucht ein Argument" STATE_DIR="$2" shift 2 ;; --max-time) [[ $# -ge 2 ]] || die "--max-time braucht ein Argument" MAX_TIME="$2" shift 2 ;; -h|--help) usage clean_up 0 ;; *) die "Unbekannte Option: $1 (verwende -h)" ;; esac done if [[ -z "$IFACE" ]]; then usage >&2 clean_up 2 fi if [[ -n "$SERVICE" && $DO_REBOOT -eq 1 ]]; then die "--restart-service und --reboot schließen sich aus" fi STATE_FILE="$STATE_DIR/$IFACE.fail" mkdir -p "$STATE_DIR" # lock gegen parallele cron-runs LOCK_FD=9 LOCK_FILE="$STATE_FILE.lock" exec {LOCK_FD}>"$LOCK_FILE" || true if command -v flock >/dev/null 2>&1; then flock -n "$LOCK_FD" || clean_up 0 fi # ------------------------------------------ # Funktion: Testet ein HTTP(S)-Ziel # ------------------------------------------ test_target() { local target="$1" $TIMEOUT_BIN $MAX_TIME $PING_BIN -I "$IFACE" -c 2 -W 2 "$target" >/dev/null 2>&1 } # ------------------------------------------ # Tests # ------------------------------------------ TOTAL="${#TARGETS[@]}" FAILED=0 blank_line || true log_info " Interface: \033[17G$IFACE" log_info " Targets (${TOTAL}):\033[17G${TARGETS[*]}" log_info " ping:\033[17G$PING_BIN timeout: ${MAX_TIME}s" blank_line || true for TG in "${TARGETS[@]}"; do if test_target "$TG"; then log_info " ${GREEN}OK${RESET} $TG" break; else FAILED=$((FAILED + 1)) log_info " ${YELLOW}FAIL${RESET} $TG" fi done # Wenn mindestens EIN Ziel funktioniert -> online if [[ $FAILED -lt $TOTAL ]]; then [[ -f "$STATE_FILE" ]] && rm -f "$STATE_FILE" if [[ $IS_TTY -eq 1 ]]; then echo "" echo -e " ${GREEN}${BOLD}OK${RESET} - Interface ${IFACE}: mindestens ein Ziel erreichbar." fi clean_up 0 fi # Alle Ziele fail -> offline # Erst beim zweiten Mal melden/handeln TS="$("$DATE_BIN" '+%F %T')" if [[ -f "$STATE_FILE" ]]; then if [[ $IS_TTY -eq 1 ]]; then log_err "" log_err " ${RED}${BOLD}FAILED${RESET} - ${TS} - Interface ${IFACE}: TCP/HTTP(S) Verbindungen nicht erreichbar! (curl; Targets: ${TARGETS[*]})" log_err "" else log_err "" log_err " ${TS} - Interface ${IFACE}: PING Verbindungen nicht erreichbar!" fi # Aktion if [[ -n "$SERVICE" ]]; then log_info " ${YELLOW}Restart Service ${BOLD}$SERVICE${RESET}" log_info "" if systemctl restart "$SERVICE" >/dev/null 2>&1; then if [[ $IS_TTY -eq 1 ]] ; then log_err " ${GREEN}Service neugestartet:${RESET} $SERVICE" else log_err " ${TS} - Service neugestartet: $SERVICE" log_err "" fi clean_up 1 else if [[ $IS_TTY -eq 1 ]] ; then log_err " ${RED}Service-Restart fehlgeschlagen:${RESET} $SERVICE" else log_err "" log_err " ${TS} - Service-Restart fehlgeschlagen: $SERVICE" log_err "" fi clean_up 3 fi elif [[ $DO_REBOOT -eq 1 ]]; then if [[ $IS_TTY -eq 1 ]]; then log_err " ${YELLOW}${BOLD}Resboot machine NOW!${RESET}" log_err "" else log_err " ${TS} - Resboot machine NOW!" log_err "" fi /sbin/reboot >/dev/null 2>&1 || { log_err "${RED}Reboot fehlgeschlagen.${RESET}"; clean_up 3; } clean_up 1 fi #clean_up 1 else # Erster Offline-Fall -> noch keine Meldung touch "$STATE_FILE" if [[ $IS_TTY -eq 1 ]]; then log_info "" log_info " ${YELLOW}${BOLD}WARN${RESET} - Interface ${IFACE} offline (das erste mal - noch keine Aktion/Meldung)." else log_err " ${TS} - Interface ${IFACE} offline (first time - no action started)" fi clean_up 0 fi