Fix: Mailbox Stats über Dovecot mit config/mailpool.php
parent
d9867db546
commit
02e558bf4b
|
|
@ -179,13 +179,48 @@ class Fail2BanCard extends Component
|
||||||
// return 600;
|
// 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
|
private function buildIpDetails(string $jail, array $ips, int $bantime): array
|
||||||
{
|
{
|
||||||
$now = time(); $out = [];
|
$now = time();
|
||||||
|
$out = [];
|
||||||
|
|
||||||
foreach ($ips as $ip) {
|
foreach ($ips as $ip) {
|
||||||
$banAt = $this->lastBanTimestamp($jail, $ip);
|
$banAt = $this->lastBanTimestamp($jail, $ip);
|
||||||
$remaining = null; $until = null;
|
$remaining = null;
|
||||||
|
$until = null;
|
||||||
|
|
||||||
if ($bantime === -1) {
|
if ($bantime === -1) {
|
||||||
$remaining = -1; // permanent
|
$remaining = -1; // permanent
|
||||||
|
|
@ -194,37 +229,15 @@ class Fail2BanCard extends Component
|
||||||
$until = $remaining > 0 ? ($banAt + $bantime) : null;
|
$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;
|
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
|
private function firstMatch(string $pattern, string $haystack): ?string
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue