whitelist feature

This commit is contained in:
Andreas Knuth 2026-03-11 19:47:37 -05:00
parent 5e4859a5c4
commit bd8efc867a
3 changed files with 99 additions and 1 deletions

View File

@ -23,4 +23,9 @@ RUN chmod +x /scripts/sync.py
COPY sieve-schedule /etc/sieve-schedule
# 5. Supervisor Konfiguration kopieren
COPY sieve-supervisor.conf /etc/supervisor/conf.d/sieve-sync.conf
COPY sieve-supervisor.conf /etc/supervisor/conf.d/sieve-sync.conf
# 6. Dynamic Whitelist Script und Supervisor-Config kopieren
COPY dynamic_whitelist.py /scripts/dynamic_whitelist.py
RUN chmod +x /scripts/dynamic_whitelist.py
COPY whitelist-supervisor.conf /etc/supervisor/conf.d/dynamic-whitelist.conf

87
DMS/dynamic_whitelist.py Normal file
View File

@ -0,0 +1,87 @@
#!/usr/bin/env python3
import os
import re
import time
import subprocess
import threading
from datetime import datetime
try:
from croniter import croniter
except ImportError:
print("Bitte 'croniter' via pip installieren!")
exit(1)
LOG_FILE = '/var/log/mail/mail.log'
WHITELIST_DURATION_SEC = 24 * 60 * 60 # 24 Stunden
CRON_SCHEDULE = "0 * * * *" # Jede Stunde
active_ips = {}
# Regex für Dovecot IMAP/POP3 erfolgreiche Logins
LOGIN_REGEX = re.compile(r"dovecot: (?:imap|pop3)-login: Login: user=<[^>]+>.*rip=([0-9]{1,3}(?:\.[0-9]{1,3}){3}),")
# Private Netze (Docker/Local) ignorieren
IGNORE_REGEX = re.compile(r"^(172\.|10\.|192\.168\.|127\.)")
def run_command(cmd):
try:
subprocess.run(cmd, shell=True, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except Exception as e:
print(f"Fehler bei: {cmd} - {e}")
def cleanup_job():
"""Cron-Thread für das stündliche Aufräumen abgelaufener IPs."""
iter = croniter(CRON_SCHEDULE, datetime.now())
while True:
next_run = iter.get_next(datetime)
sleep_seconds = (next_run - datetime.now()).total_seconds()
if sleep_seconds > 0:
time.sleep(sleep_seconds)
print(f"[{datetime.now()}] Starte stündlichen Whitelist-Cleanup...")
now = time.time()
expired_ips = [ip for ip, timestamp in active_ips.items() if now - timestamp > WHITELIST_DURATION_SEC]
for ip in expired_ips:
print(f"[{datetime.now()}] Whitelist für {ip} abgelaufen. Entferne...")
run_command(f"fail2ban-client set dovecot delignoreip {ip}")
run_command(f"fail2ban-client set postfix delignoreip {ip}")
del active_ips[ip]
def follow_log():
"""Verwendet System 'tail -F', da dies Log-Rotation automatisch handhabt."""
print(f"[{datetime.now()}] Dynamic Whitelist Monitor gestartet...")
while not os.path.exists(LOG_FILE):
time.sleep(2)
process = subprocess.Popen(['tail', '-F', LOG_FILE], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True)
for line in process.stdout:
match = LOGIN_REGEX.search(line)
if match:
ip = match.group(1)
if IGNORE_REGEX.match(ip):
continue
now = time.time()
# Neue IP in die Fail2ban Whitelist eintragen
if ip not in active_ips:
print(f"[{datetime.now()}] Neuer erfolgreicher Login von {ip}. Setze auf Whitelist...")
run_command(f"fail2ban-client set dovecot addignoreip {ip}")
run_command(f"fail2ban-client set postfix addignoreip {ip}")
# Timestamp (Last Seen) aktualisieren
active_ips[ip] = now
if __name__ == '__main__':
# Warte kurz, bis Fail2ban nach einem Container-Start hochgefahren ist
time.sleep(15)
# Cron-Cleanup im Hintergrund starten
threading.Thread(target=cleanup_job, daemon=True).start()
# Log-Überwachung in der Endlosschleife starten
follow_log()

View File

@ -0,0 +1,6 @@
[program:dynamic-whitelist]
command=/usr/bin/python3 -u /scripts/dynamic_whitelist.py
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/dynamic-whitelist.err.log
stdout_logfile=/var/log/supervisor/dynamic-whitelist.out.log