Fix: Mailbox Stats über Dovecot mit config/mailpool.php

main
boban 2025-10-31 00:59:51 +01:00
parent d9867db546
commit 02e558bf4b
1 changed files with 44 additions and 31 deletions

View File

@ -179,13 +179,48 @@ class Fail2BanCard extends Component
// return 600;
// }
/** baut Detail-Liste inkl. Restzeit */
/** Letzten Ban-Zeitpunkt (Unix-Timestamp) aus /var/log/fail2ban.log ermitteln. */
private function lastBanTimestamp(string $jail, string $ip): ?int
{
$file = '/var/log/fail2ban.log';
if (!is_readable($file)) return null;
// nur das Ende der Datei lesen (Performance, auch bei Rotation groß genug wählen)
$tailBytes = 400000; // 400 KB
$size = @filesize($file) ?: 0;
$seek = max(0, $size - $tailBytes);
$fh = @fopen($file, 'rb');
if (!$fh) return null;
if ($seek > 0) fseek($fh, $seek);
$data = stream_get_contents($fh) ?: '';
fclose($fh);
// Beispielzeile:
// 2025-10-30 22:34:20,797 fail2ban.actions [...] NOTICE [sshd] Ban 193.46.255.244
$j = preg_quote($jail, '/');
$p = preg_quote($ip, '/');
$pattern = '/^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2}),\d+.*\['.$j.'\]\s+Ban\s+'.$p.'\s*$/m';
if (preg_match_all($pattern, $data, $m) && !empty($m[1])) {
$date = end($m[1]); // YYYY-MM-DD
$time = end($m[2]); // HH:MM:SS
$dt = \DateTime::createFromFormat('Y-m-d H:i:s', "$date $time", new \DateTimeZone(date_default_timezone_get()));
return $dt ? $dt->getTimestamp() : null;
}
return null;
}
/** Baut Details inkl. Restzeit (Sekunden; -1 = permanent). */
private function buildIpDetails(string $jail, array $ips, int $bantime): array
{
$now = time(); $out = [];
$now = time();
$out = [];
foreach ($ips as $ip) {
$banAt = $this->lastBanTimestamp($jail, $ip);
$remaining = null; $until = null;
$remaining = null;
$until = null;
if ($bantime === -1) {
$remaining = -1; // permanent
@ -194,37 +229,15 @@ class Fail2BanCard extends Component
$until = $remaining > 0 ? ($banAt + $bantime) : null;
}
$out[] = ['ip' => $ip, 'remaining' => $remaining, 'until' => $until];
$out[] = [
'ip' => $ip,
'remaining' => $remaining, // -1 = permanent, null = Ban-Zeitpunkt nicht gefunden, >=0 = Sekunden
'until' => $until, // Unix-Timestamp oder null
];
}
return $out;
}
/** letzte "Ban <IP>"-Zeile finden (Log + Rotation + journald), liefert Unix-Timestamp oder null */
private function lastBanTimestamp(string $jail, string $ip): ?int
{
// 1) zgrep in /var/log/fail2ban.log*
$line = (string)@shell_exec(
"zgrep -h -E '\\[{$jail}\\]\\s+Ban\\s+{$ip}' /var/log/fail2ban.log* 2>/dev/null | tail -n 1"
);
$line = trim($line);
// 2) Fallback: journald
if ($line === '') {
$line = (string)@shell_exec(
"journalctl -u fail2ban --since '14 days ago' 2>/dev/null | grep -F '[{$jail}] Ban {$ip}' | tail -n 1"
);
$line = trim($line);
}
if ($line === '') return null;
// "YYYY-MM-DD HH:MM:SS,mmm ..." oder ISO im Text
if (preg_match('/^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})/', $line, $m)
|| preg_match('/(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})/', $line, $m)) {
$ts = strtotime($m[1].' '.$m[2]);
return $ts ?: null;
}
return null;
}
private function firstMatch(string $pattern, string $haystack): ?string
{