From c9c8b775087dca63ce6d5b27eaa32e37d893f29d Mon Sep 17 00:00:00 2001 From: Kai Date: Tue, 21 Apr 2026 08:40:20 +0100 Subject: [PATCH] Initial commit: pingu scripts --- .gitignore | 3 + scripts/ssh-analyzer.sh | 50 ++++++++++++++ scripts/update.sh | 148 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 .gitignore create mode 100755 scripts/ssh-analyzer.sh create mode 100755 scripts/update.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1218df7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +logs/ +*.log +config/*.env diff --git a/scripts/ssh-analyzer.sh b/scripts/ssh-analyzer.sh new file mode 100755 index 0000000..1645f3c --- /dev/null +++ b/scripts/ssh-analyzer.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +TOKEN="8101319618:AAHboFVVgmLPccJB0MDr_R2g0K90hkGqkRw" +CHAT_ID="581059353" + +PIS=("192.168.178.2" "192.168.178.3" "localhost") + +STATE_FILE="/home/kai/.ssh-monitor-lastcheck" + +if [ ! -f "$STATE_FILE" ]; then + date --iso-8601=seconds > "$STATE_FILE" +fi + +LAST_CHECK=$(cat "$STATE_FILE") +NOW=$(date --iso-8601=seconds) + +for PI in "${PIS[@]}" +do + if [ "$PI" == "localhost" ]; then + LOG=$(journalctl -u ssh --since "$LAST_CHECK" --no-pager) + HOST=$(hostname) + else + LOG=$(ssh -o ConnectTimeout=5 kai@$PI \ + "journalctl -u ssh --since \"$LAST_CHECK\" --no-pager") + + HOST=$(ssh kai@$PI hostname) + fi + + FAILS=$(echo "$LOG" | grep "Failed password" | wc -l) + + if [ "$FAILS" -gt 0 ]; then + + IPS=$(echo "$LOG" | grep "Failed password" \ + | awk '{print $(NF-3)}' \ + | sort | uniq -c | sort -nr) + + MESSAGE="🚨 SSH Angriff erkannt! +Host: $HOST ($PI) +Fehlversuche: $FAILS + +Top Angreifer: +$IPS" + + curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \ + -d chat_id="$CHAT_ID" \ + -d text="$MESSAGE" + fi +done + +echo "$NOW" > "$STATE_FILE" diff --git a/scripts/update.sh b/scripts/update.sh new file mode 100755 index 0000000..e778f9a --- /dev/null +++ b/scripts/update.sh @@ -0,0 +1,148 @@ +#!/bin/bash +set -Eeuo pipefail + +HOST="$(hostname)" +LOG="/opt/pingu/logs/update.log" + +TELEGRAM_TOKEN="${TELEGRAM_TOKEN:-8101319618:AAHboFVVgmLPccJB0MDr_R2g0K90hkGqkRw}" +TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-581059353}" + +REBOOT=0 +DOCKER_UPDATES=0 +DOCKER_UPDATE_LIST="" + +log() { + local msg="$1" + echo "[$(date '+%F %T')] $msg" | tee -a "$LOG" +} + +send_telegram() { + local text="$1" + local http_code + + http_code="$(curl -sS --show-error \ + -o /tmp/pingu-telegram-response.txt \ + -w '%{http_code}' \ + -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \ + --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \ + --data-urlencode "text=${text}")" + + cat /tmp/pingu-telegram-response.txt >> "$LOG" + echo >> "$LOG" + + if [ "$http_code" -ne 200 ]; then + log "Telegram-API Fehler, HTTP ${http_code}" + return 1 + fi +} + +cleanup_on_error() { + local exit_code=$? + local line_no="${1:-unknown}" + + log "FEHLER in Zeile ${line_no}, Exit-Code ${exit_code}" + + curl -sS -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \ + --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \ + --data-urlencode "text=❌ ${HOST}: Update-Script fehlgeschlagen in Zeile ${line_no} (Exit ${exit_code})." \ + >> "$LOG" 2>&1 || true + + exit "$exit_code" +} + +trap 'cleanup_on_error ${LINENO}' ERR + +check_docker_updates() { + if ! command -v docker >/dev/null 2>&1; then + log "Docker nicht installiert - überspringe Container-Prüfung" + return 0 + fi + + if ! docker info >/dev/null 2>&1; then + log "Docker-Daemon nicht erreichbar - überspringe Container-Prüfung" + return 0 + fi + + local container_ids + mapfile -t container_ids < <(docker ps -q) + + if [ "${#container_ids[@]}" -eq 0 ]; then + log "Keine laufenden Docker-Container gefunden" + return 0 + fi + + log "Prüfe ${#container_ids[@]} laufende Docker-Container auf Image-Updates" + + local cid name image running_id latest_id pull_output + for cid in "${container_ids[@]}"; do + name="$(docker inspect --format '{{.Name}}' "$cid" | sed 's#^/##')" + image="$(docker inspect --format '{{.Config.Image}}' "$cid")" + running_id="$(docker inspect --format '{{.Image}}' "$cid")" + + log "Prüfe Container ${name} mit Image ${image}" + + if pull_output="$(docker pull "$image" 2>&1)"; then + latest_id="$(docker image inspect --format '{{.Id}}' "$image")" + + if [ "$running_id" != "$latest_id" ]; then + DOCKER_UPDATES=$((DOCKER_UPDATES + 1)) + DOCKER_UPDATE_LIST+=$'\n'"🐳 ${name} (${image})" + log "Update verfügbar für ${name}" + else + log "Kein Update für ${name}" + fi + else + log "Konnte Image ${image} für ${name} nicht prüfen: ${pull_output}" + fi + done +} + +main() { + touch "$LOG" + chmod 600 "$LOG" + + log "=== Update Start ${HOST} ===" + + export DEBIAN_FRONTEND=noninteractive + + log "Starte apt-get update" + apt-get update >> "$LOG" 2>&1 + + log "Starte apt-get upgrade" + apt-get -y upgrade >> "$LOG" 2>&1 + + if [ -f /var/run/reboot-required ]; then + REBOOT=1 + log "Reboot erforderlich" + else + log "Kein Reboot erforderlich" + fi + + check_docker_updates + + local msg="🐧 ${HOST}: Updates installiert." + if [ "$REBOOT" -eq 1 ]; then + msg="${msg} REBOOT erforderlich." + else + msg="${msg} Kein Reboot nötig." + fi + + if [ "$DOCKER_UPDATES" -gt 0 ]; then + msg+=$'\n\n'"🐳 Docker-Updates verfügbar: ${DOCKER_UPDATES}${DOCKER_UPDATE_LIST}" + else + msg+=$'\n\n'"🐳 Docker-Container aktuell." + fi + + log "Sende Telegram-Nachricht" + send_telegram "$msg" + + log "$msg" + log "=== Update Ende ${HOST} ===" + + if [ "$REBOOT" -eq 1 ]; then + log "System wird neu gestartet" + reboot + fi +} + +main "$@"