parent
792f0e3528
commit
81860d1851
|
|
@ -21,31 +21,48 @@ class Fail2BanJailModal extends ModalComponent
|
|||
{
|
||||
$jail = $this->jail;
|
||||
|
||||
[, $s] = $this->f2b('status '.escapeshellarg($jail));
|
||||
$ipList = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
$ips = $ipList !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipList)))) : [];
|
||||
[, $s] = $this->f2b('status '.escapeshellarg($jail));
|
||||
$ipList = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
$ips = $ipList !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipList)))) : [];
|
||||
|
||||
$bantime = $this->getBantime($jail);
|
||||
$defaultBantime = $this->getBantime($jail);
|
||||
|
||||
$rows = [];
|
||||
foreach ($ips as $ip) {
|
||||
$banAt = $this->lastBanTimestamp($jail, $ip); // Unix-Timestamp oder null
|
||||
$banAt = null; $until = null; $remaining = null;
|
||||
|
||||
$remaining = null; $until = null;
|
||||
if ($bantime === -1) {
|
||||
$remaining = -1; // permanent
|
||||
} elseif ($banAt !== null) {
|
||||
$remaining = max(0, $bantime - (time() - $banAt));
|
||||
$until = $remaining > 0 ? $banAt + $bantime : null;
|
||||
} else {
|
||||
$remaining = -2; // ≈ Approximation (Bantime bekannt, Start unbekannt)
|
||||
// 1) Primärquelle: DB
|
||||
if ($info = $this->banInfoFromDb($jail, $ip)) {
|
||||
$banAt = $info['banned_at'];
|
||||
if ((int)$info['expire'] === -1) {
|
||||
$remaining = -1; // permanent
|
||||
} elseif ((int)$info['expire'] > 0) {
|
||||
$until = (int)$info['expire'];
|
||||
$remaining = max(0, $until - time());
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Fallback: Log + Jail-Bantime
|
||||
if ($remaining === null) {
|
||||
$banAt = $banAt ?? $this->lastBanTimestamp($jail, $ip);
|
||||
if ($banAt !== null) {
|
||||
$remaining = max(0, $defaultBantime - (time() - $banAt));
|
||||
$until = $remaining > 0 ? $banAt + $defaultBantime : null;
|
||||
} else {
|
||||
$remaining = -2; // ~approx
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Wenn 0 Sekunden, aber Fail2Ban hält die IP noch → „verlängert/unbekannt“
|
||||
if ($remaining === 0 && $this->isStillBanned($jail, $ip)) {
|
||||
$remaining = -2; // markiere als „~ unbekannt/verlängert“
|
||||
}
|
||||
|
||||
[$timeText, $metaText, $boxClass] = $this->present($remaining, $banAt, $until);
|
||||
|
||||
$rows[] = [
|
||||
'ip' => $ip,
|
||||
'bantime' => $bantime,
|
||||
'bantime' => $defaultBantime,
|
||||
'banned_at' => $banAt,
|
||||
'remaining' => $remaining,
|
||||
'until' => $until,
|
||||
|
|
@ -57,7 +74,7 @@ class Fail2BanJailModal extends ModalComponent
|
|||
|
||||
$this->rows = $rows;
|
||||
}
|
||||
|
||||
|
||||
/** ROBUST: findet Binaries automatisch */
|
||||
private function bin(string $name): string
|
||||
{
|
||||
|
|
@ -117,6 +134,18 @@ class Fail2BanJailModal extends ModalComponent
|
|||
return null;
|
||||
}
|
||||
|
||||
private function getDbFile(): string
|
||||
{
|
||||
[, $out] = $this->f2b('get dbfile');
|
||||
$path = trim($out);
|
||||
return $path !== '' ? $path : '/var/lib/fail2ban/fail2ban.sqlite3';
|
||||
}
|
||||
|
||||
private function sql(string $s): string
|
||||
{
|
||||
return "'".str_replace("'", "''", $s)."'";
|
||||
}
|
||||
|
||||
/** Darstellung: permanent / Restzeit / abgelaufen / ~approx / unbekannt */
|
||||
private function present(?int $remaining, ?int $banAt, ?int $until): array
|
||||
{
|
||||
|
|
@ -155,6 +184,33 @@ class Fail2BanJailModal extends ModalComponent
|
|||
return [$ok, $out];
|
||||
}
|
||||
|
||||
private function banInfoFromDb(string $jail, string $ip): ?array
|
||||
{
|
||||
$sudo = $this->bin('sudo');
|
||||
$sqlite = $this->bin('sqlite3');
|
||||
$db = $this->getDbFile();
|
||||
|
||||
$q = sprintf(
|
||||
"SELECT timeofban, expiretime FROM bans WHERE jail=%s AND ip=%s ORDER BY timeofban DESC LIMIT 1",
|
||||
$this->sql($jail),
|
||||
$this->sql($ip)
|
||||
);
|
||||
|
||||
$cmd = "$sudo -n $sqlite -readonly ".escapeshellarg($db).' '.escapeshellarg($q);
|
||||
$out = trim((string)@shell_exec($cmd));
|
||||
if ($out === '') return null;
|
||||
|
||||
[$timeofban, $expire] = array_map('intval', explode('|', $out)) + [null, null];
|
||||
return ['banned_at' => $timeofban ?: null, 'expire' => $expire ?? null];
|
||||
}
|
||||
|
||||
private function isStillBanned(string $jail, string $ip): bool
|
||||
{
|
||||
[, $out] = $this->f2b('get '.escapeshellarg($jail).' banip '.escapeshellarg($ip));
|
||||
// gibt in der Regel "1" (banned) oder nichts/0 zurück
|
||||
return (bool)preg_match('/\b1\b/', $out);
|
||||
}
|
||||
|
||||
private function getBantime(string $jail): int
|
||||
{
|
||||
[, $out] = $this->f2b('get '.escapeshellarg($jail).' bantime');
|
||||
|
|
|
|||
Loading…
Reference in New Issue