Ein Wiki privater Natur

remaining_ban_time

remaining_ban_time ist ein kleines, aber feines Tool zur fail2ban Administration.

Das Script wird ohne Parameter gestartet und fragt das Jail ab,
oder man übergibt das Jail als Parameter.

Es werden die momentan gebannte IPs angezeigt und die verbliebene Bantime ausgegeben.

Mit dem Script kann man indirekt sehr gut die Funktion der default Parameter in jail.local prüfen.
Z.B.
bantime.increment = true
bantime.rndtime = 30m
bantime.maxtime = 60d
... usw. ...
Genaueres zu den Default Parametern hier: fail2ban
remaining_ban_time.png
Damit ist das Script sehr nützlich zur Überprüfung, ob die Einstellungen so skalieren, wie erwartet.

#!/bin/bash
# remaining_ban_time.sh
# by bed and chatgpt 4.o
# $Revision: 1.10 $
# Dieses Skript sollte jetzt genauer funktionieren und auch Bannzeitverlängerungen
# korrekt erkennen und verarbeiten.

# Funktion zur Anzeige der Gebrauchsanweisung
usage() {
    echo "Usage: $0 [<jail>]"
    echo "Available jails:"
    for jail in "${JAILS[@]}"; do
        echo "  - $jail"
    done
    exit 1
}

# Hole die Liste der Jails aus dem fail2ban-client status Befehl
jails_list=$(fail2ban-client status | grep 'Jail list:' | cut -d: -f2 | tr ',' '\n' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/^/"/; s/$/"/')

# Erzeuge das Bash-Array
echo "JAILS=(" > jails_array.sh
for jail in $jails_list; do
    echo "    $jail" >> jails_array.sh
done
echo ")" >> jails_array.sh

# Source die generierte Datei, um die JAILS-Variable zu definieren
source jails_array.sh

# Pfad zur fail2ban-client ausführen
FAIL2BAN_CLIENT="$(command -v fail2ban-client)"

# Überprüfen, ob fail2ban-client installiert ist
if [ -z "${FAIL2BAN_CLIENT}" ]; then
  echo "fail2ban-client nicht gefunden. Stelle sicher, dass fail2ban installiert ist."
  exit 1
fi

# Wenn kein Jail-Parameter übergeben wurde, Dialog anzeigen
if [ -z "$1" ]; then
    echo "Bitte wähle einen Jail aus:"
    select jail_name in "${JAILS[@]}"; do
        if [ -n "$jail_name" ]; then
            JAIL_NAME="$jail_name"
            break
        else
            echo "Ungültige Auswahl. Bitte wähle erneut."
            echo "Abbruch mit CTRL-C"
        fi
    done
else
    # Jail-Parameter übergeben, prüfen ob gültig
    if [[ " ${JAILS[@]} " =~ " $1 " ]]; then
        JAIL_NAME="$1"
    else
        echo "Ungültiger Jail: $1"
        usage
    fi
fi

echo "Gebannte IPs und ihre verbleibende Bannzeit in $JAIL_NAME:"

# Dauer der Banns in Sekunden (anpassen, wenn nötig)
BAN_DURATION=$(fail2ban-client get $JAIL_NAME bantime)

# Aktuelle Zeit in Sekunden seit Epoche
CURRENT_TIME=$(date +%s)

# Alle gebannten IPs aus dem Jail auslesen
BANNED_IPS=$(fail2ban-client status $JAIL_NAME | grep 'Banned IP list' | cut -d ':' -f 2)

# Wenn keine IPs gebannt sind, Skript beenden
if [ -z "$BANNED_IPS" ]; then
  echo "Keine IPs gebannt in $JAIL_NAME"
  exit 0
fi

# Gebannte IPs in ein Array umwandeln
IFS=', ' read -r -a IP_ARRAY <<< "$BANNED_IPS"

# Durch jede gebannte IP iterieren
for IP in "${IP_ARRAY[@]}"; do
  IP=$(echo "$IP" | sed 's/^[[:blank:]]*//')
  
  # Suche nach dem letzten Bannzeitpunkt in den Logs
  LOG_TIME=$(egrep ".*${IP}" /var/log/fail2ban.log /var/log/fail2ban.log.1 | grep "Ban ${IP}" | tail -1 | cut -d ' ' -f 1-2 | sed 's/,.*//')

  # Wenn keine Bannzeit gefunden wurde, überspringen
  if [ -z "$LOG_TIME" ]; then
 #   echo "Fehler bei der Verarbeitung des Zeitstempels für IP: $IP"
    continue
  fi
  
  # Umwandeln in Sekunden seit Epoche
  LOG_TIMESTAMP=$(date -d "$LOG_TIME" +%s 2>/dev/null)
  
  # Berechnung der verbleibenden Bannzeit
  EXPIRE_TIME=$((LOG_TIMESTAMP + BAN_DURATION))
  REMAINING_TIME=$((EXPIRE_TIME - CURRENT_TIME))

  # Debug-Ausgabe
#  echo "DEBUG: IP=$IP LOG_TIMESTAMP=$LOG_TIMESTAMP EXPIRE_TIME=$EXPIRE_TIME REMAINING_TIME=$REMAINING_TIME"

  # Wenn die verbleibende Zeit negativ ist, prüfe auf erneuten Bann
  if [ $REMAINING_TIME -le 0 ]; then
    # Überprüfe, ob es eine Verlängerung gibt
    LOG_TIME=$(egrep ".*${IP}" /var/log/fail2ban.log /var/log/fail2ban.log.1 | grep "Increase Ban ${IP}" | tail -1 | awk -F '->' '{print $2}' | sed 's/[()]//g')
    if [ -n "$LOG_TIME" ]; then
      LOG_TIMESTAMP=$(date -d "$LOG_TIME" +%s 2>/dev/null)
      REMAINING_TIME=$((LOG_TIMESTAMP - CURRENT_TIME))
    else
      echo "IP: $IP - Bann bereits abgelaufen"
      continue
    fi
  fi

  # Berechnung der Stunden und Tage
  if [ $REMAINING_TIME -gt $((24 * 3600)) ]; then
    REMAINING_DAYS=$((REMAINING_TIME / (24 * 3600)))
    REMAINING_HOURS=$(( (REMAINING_TIME % (24 * 3600)) / 3600 ))
    printf "\rIP: %-15s - Verbleibende Zeit: %02d Tage %02d Stunden\n" "$IP" "$REMAINING_DAYS" "$REMAINING_HOURS"
  elif [ $REMAINING_TIME -gt 7200 ]; then  # Mehr als 2 Stunden
    REMAINING_HOURS=$((REMAINING_TIME / 3600))
    printf "\rIP: %-15s - Verbleibende Zeit: %02d Stunden\n" "$IP" "$REMAINING_HOURS"
  else
    REMAINING_MINUTES=$((REMAINING_TIME / 60))
    printf "\rIP: %-15s - Verbleibende Zeit: %02d Minuten\n" "$IP" "$REMAINING_MINUTES"
  fi
done

echo # Neue Zeile für bessere Darstellung nach dem Fortschrittsanzeichen

Optimierung der Log-Zeit-Berechnung für Fail2Ban-Skript

Durch die jüngste Änderung am Skript (Rev 1.10) habe ich die Berechnung von LOG_TIME optimiert. Die ursprüngliche Methode war anfällig für Fehler bei der Sonntags-Log-Rotation, da sie nur das aktuelle Datum bei der Abfrage berücksichtigte.

Mit der neuen Methode wird nun sowohl in der aktuellen Log-Datei (/var/log/fail2ban.log) als auch in der rotierte Log-Datei (/var/log/fail2ban.log.1) nach der IP-Adresse gesucht. Dies stellt sicher, dass auch Einträge vor der Log-Rotation korrekt berücksichtigt werden. Hierdurch konnte die Präzision des Skripts weiter gesteigert werden, insbesondere in Umgebungen mit langen Bannzeiten.