commit bab3ac4cc49f0c4f4f1569d848c8cd11d364556b Author: Thorsten Date: Tue May 12 15:51:17 2026 +0200 Initial commit diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..1b1ea45 --- /dev/null +++ b/README.MD @@ -0,0 +1,37 @@ +# f2b-docker-unblock + +Kleines CLI-Tool zum schnellen **Entbannen aller IPs in allen Fail2Ban-Jails** – optimiert fΓΌr Docker-Setups (z. B. mit Traefik). + +--- + +## ✨ Features + +- πŸ”“ Entfernt **alle gebannten IPs** aus allen Jails +- 🐳 UnterstΓΌtzt **Fail2Ban im Docker-Container** +- πŸ” Erkennt Container automatisch (oder manuell ΓΌbergeben) +- βœ… Verifiziert, ob Unban erfolgreich war +- πŸ’¬ Klare, farbige Ausgabe mit Emojis +- πŸ›‘οΈ Fehlerresistent (bricht nicht bei Einzelproblemen ab) + +--- + +## πŸ“¦ Installation + +### 1. Script speichern + +Empfohlener Speicherort: + +```bash +/usr/local/bin/f2b-docker-unblock +``` +### 1. Script ausfΓΌhrbar machen + +```bash +chmod +x /usr/local/bin/f2b-docker-unblock +``` + +## πŸ“¦ AusfΓΌhren + +```bash +f2b-docker-unblock [optional FAIL2BAN_CONTAINER] +``` \ No newline at end of file diff --git a/f2b-docker b/f2b-docker new file mode 100644 index 0000000..cf5ae4a --- /dev/null +++ b/f2b-docker @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +CACHE_FILE="/tmp/f2b-container" + +resolve_container() { + # 1. Versuch: Compose Label + local c + c=$(docker ps \ + --filter "label=com.docker.compose.service=fail2ban" \ + --format '{{.Names}}' \ + | head -n 1) + + if [[ -n "$c" ]]; then + echo "$c" + return + fi + + # 2. Fallback: Kandidaten + local CANDIDATES=("fail2ban" "fail-2-ban" "f2b") + + for name in "${CANDIDATES[@]}"; do + if docker ps --format '{{.Names}}' | grep -qx "$name"; then + echo "$name" + return + fi + done + + return 1 +} + +# --- Cache verwenden --- +if [[ -f "$CACHE_FILE" ]]; then + CONTAINER=$(<"$CACHE_FILE") + + # prΓΌfen ob er noch lΓ€uft + if ! docker ps --format '{{.Names}}' | grep -qx "$CONTAINER"; then + CONTAINER="" + fi +else + CONTAINER="" +fi + +# --- neu auflΓΆsen wenn nΓΆtig --- +if [[ -z "${CONTAINER:-}" ]]; then + CONTAINER=$(resolve_container || true) + + if [[ -z "$CONTAINER" ]]; then + echo "❌ Kein fail2ban-Container gefunden" + exit 1 + fi + + echo "$CONTAINER" > "$CACHE_FILE" +fi + +# --- Aufruf --- +if [[ $# -eq 0 ]]; then + docker exec -i "$CONTAINER" fail2ban-client -h +else + docker exec -i "$CONTAINER" fail2ban-client "$@" +fi \ No newline at end of file diff --git a/f2b-docker-unblock b/f2b-docker-unblock new file mode 100644 index 0000000..1acb15e --- /dev/null +++ b/f2b-docker-unblock @@ -0,0 +1,97 @@ +#!/bin/bash + +set -uo pipefail + +ok() { echo -e "βœ… $1"; } +info() { echo -e "ℹ️ $1"; } +warn() { echo -e "⚠️ $1"; } +err() { echo -e "❌ $1"; } + + + +echo "" +echo "──────────────────────────────────────────────────────────" + +# Wenn kein Container angegeben β†’ automatisch suchen +if [[ $# -eq 0 ]]; then + + + info "Kein fail2ban Container angegeben, versuche Autodetect" + + CONTAINER=$(docker ps --format '{{.Names}}' | grep -i fail2ban | head -n1) + + if [[ -z "$CONTAINER" ]]; then + err "Kein Fail2Ban Container gefunden" + echo "──────────────────────────────────────────────────────────" + exit 1 + else + info "Container gefunden" + + fi +else + CONTAINER="$1" + + # Existiert der Container ΓΌberhaupt? + if ! docker ps -a --format '{{.Names}}' | grep -Fxq "$CONTAINER"; then + err "Container '$CONTAINER' existiert nicht" + echo "──────────────────────────────────────────────────────────" + exit 1 + fi + + # LΓ€uft der Container? + if ! docker ps --format '{{.Names}}' | grep -Fxq "$CONTAINER"; then + err "Container '$CONTAINER' lΓ€uft nicht" + echo "──────────────────────────────────────────────────────────" + exit 1 + fi +fi + + +info "Verwende Container: $CONTAINER" +echo "──────────────────────────────────────────────────────────" +echo "" + +JAILS=$(docker exec "$CONTAINER" fail2ban-client status \ + | awk -F: '/Jail list/ {print $2}' | xargs) + +IFS=',' read -ra JAIL_ARRAY <<< "$JAILS" + +for JAIL in "${JAIL_ARRAY[@]}"; do + JAIL=$(echo "$JAIL" | xargs) + + IPS=$(docker exec "$CONTAINER" fail2ban-client status "$JAIL" \ + | awk -F: '/Banned IP list/ {print $2}' | xargs) + + if [[ -z "$IPS" ]]; then + ok "$JAIL β†’ keine Bans" + continue + fi + + info "πŸ”“ $JAIL β†’ entbanne: $IPS" + + COUNT=0 + FAILED=0 + + for IP in $IPS; do + if docker exec "$CONTAINER" fail2ban-client set "$JAIL" unbanip "$IP" >/dev/null 2>&1; then + ((COUNT++)) + else + ((FAILED++)) + warn "$JAIL β†’ konnte $IP nicht entbannen" + fi + done + + REMAINING=$(docker exec "$CONTAINER" fail2ban-client status "$JAIL" \ + | awk '/Currently banned/ {print $4}') + + if [[ "$REMAINING" == "0" ]]; then + ok "$JAIL β†’ $COUNT IP(s) entfernt" + else + err "$JAIL β†’ $REMAINING IP(s) noch gebannt" + fi +done + +echo "" +echo "──────────────────────────────────────────────────────────" +ok "Fertig." +echo "──────────────────────────────────────────────────────────" \ No newline at end of file