whitelist helper
This commit is contained in:
parent
c2d4903bc9
commit
610b01eee7
|
|
@ -24,3 +24,8 @@ COPY sieve-schedule /etc/sieve-schedule
|
||||||
|
|
||||||
# 5. Supervisor Konfiguration kopieren
|
# 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
|
||||||
|
|
@ -55,7 +55,7 @@ services:
|
||||||
# 2. ClamAV deaktivieren (Anti-Virus)
|
# 2. ClamAV deaktivieren (Anti-Virus)
|
||||||
- ENABLE_CLAMAV=0
|
- ENABLE_CLAMAV=0
|
||||||
# HACKERSCHUTZ (Pflicht!)
|
# HACKERSCHUTZ (Pflicht!)
|
||||||
- ENABLE_FAIL2BAN=0
|
- ENABLE_FAIL2BAN=1
|
||||||
# DNS Resolver (verhindert Spamhaus-Probleme)
|
# DNS Resolver (verhindert Spamhaus-Probleme)
|
||||||
- ENABLE_UNBOUND=1
|
- ENABLE_UNBOUND=1
|
||||||
# #### END SPAM SECTION #####
|
# #### END SPAM SECTION #####
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
[program:dynamic-whitelist]
|
||||||
|
command=/usr/bin/python3 /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
|
||||||
Loading…
Reference in New Issue