parent
385b67c3c5
commit
e3c7e8de33
|
|
@ -6,29 +6,45 @@ use Livewire\Component;
|
|||
|
||||
class Fail2BanCard extends Component
|
||||
{
|
||||
public bool $available = true;
|
||||
public bool $permDenied = false; // neu
|
||||
public int $activeBans = 0;
|
||||
public array $jails = [];
|
||||
public array $topIps = [];
|
||||
public bool $available = true; // fail2ban-client vorhanden?
|
||||
public bool $permDenied = false; // Socket/Root-Rechte fehlen?
|
||||
public int $activeBans = 0; // Summe gebannter IPs über alle Jails
|
||||
public array $jails = []; // [['name'=>'sshd','banned'=>2,'ips'=>['1.2.3.4',...]], ...]
|
||||
public array $topIps = []; // [['ip'=>'x.x.x.x','count'=>N], ...]
|
||||
|
||||
// ...
|
||||
public function mount(): void
|
||||
{
|
||||
$this->load();
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.ui.security.fail2-ban-card');
|
||||
}
|
||||
|
||||
// Wird vom Button "Neu prüfen" genutzt
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->load(true);
|
||||
}
|
||||
|
||||
/* --------------------- intern --------------------- */
|
||||
|
||||
protected function load(bool $force = false): void
|
||||
{
|
||||
// existiert fail2ban-client?
|
||||
$bin = trim((string) @shell_exec('command -v fail2ban-client 2>/dev/null')) ?: '';
|
||||
if ($bin === '') {
|
||||
$this->available = false;
|
||||
$this->available = false;
|
||||
$this->permDenied = false;
|
||||
$this->activeBans = 0;
|
||||
$this->jails = [];
|
||||
$this->topIps = [];
|
||||
$this->jails = [];
|
||||
$this->topIps = [];
|
||||
return;
|
||||
}
|
||||
|
||||
// ping → prüft zugleich Rechte (liefert Fehlertext, wenn Socket gesperrt)
|
||||
[$ok, $raw] = $this->f2b('ping'); // ok==true wenn "pong"
|
||||
|
||||
// ping → prüft zugleich Rechte (bei Permission-Fehler kommt Klartext)
|
||||
[$ok, $raw] = $this->f2b('ping'); // ok == "pong" erkannt
|
||||
if (!$ok && stripos($raw, 'permission denied') !== false) {
|
||||
$this->available = true;
|
||||
$this->permDenied = true;
|
||||
|
|
@ -38,7 +54,7 @@ class Fail2BanCard extends Component
|
|||
return;
|
||||
}
|
||||
|
||||
// Jails
|
||||
// Jails auflisten
|
||||
[, $status] = $this->f2b('status');
|
||||
$jailsLn = $this->firstMatch('/Jail list:\s*(.+)$/mi', $status);
|
||||
$jails = $jailsLn ? array_filter(array_map('trim', preg_split('/\s*,\s*/', $jailsLn))) : [];
|
||||
|
|
@ -60,13 +76,13 @@ class Fail2BanCard extends Component
|
|||
$this->topIps = $this->collectTopIps();
|
||||
}
|
||||
|
||||
/** führt fail2ban-client aus; mit sudo-Fallback; gibt [ok, output] zurück */
|
||||
/** führt fail2ban-client via sudo aus; gibt [ok, output] zurück */
|
||||
private function f2b(string $args): array
|
||||
{
|
||||
$sudo = '/usr/bin/sudo';
|
||||
$f2b = '/usr/bin/fail2ban-client';
|
||||
$cmd = "timeout 2 $sudo -n $f2b $args 2>&1";
|
||||
$out = (string) @shell_exec($cmd);
|
||||
$sudo = '/usr/bin/sudo';
|
||||
$f2b = '/usr/bin/fail2ban-client';
|
||||
$cmd = "timeout 2 $sudo -n $f2b $args 2>&1";
|
||||
$out = (string) @shell_exec($cmd);
|
||||
|
||||
$ok = stripos($out, 'Status') !== false
|
||||
|| stripos($out, 'Jail list') !== false
|
||||
|
|
@ -80,9 +96,22 @@ class Fail2BanCard extends Component
|
|||
return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null;
|
||||
}
|
||||
|
||||
/** Zählt die häufigsten IPs aus den letzten Fail2Ban-Logs (ban/unban Events) */
|
||||
private function collectTopIps(): array
|
||||
{
|
||||
// … (deine vorhandene Methode aus meiner letzten Antwort – passt)
|
||||
// lässt du unverändert.
|
||||
// Zieh nur fail2ban.log, nicht auth/mail – präziser & schneller
|
||||
$cmd = 'tail -n 2000 /var/log/fail2ban.log 2>/dev/null'
|
||||
. ' | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}"'
|
||||
. ' | sort | uniq -c | sort -nr | head -5';
|
||||
$log = (string) @shell_exec($cmd);
|
||||
$rows = [];
|
||||
if ($log !== '') {
|
||||
foreach (preg_split('/\R+/', trim($log)) as $l) {
|
||||
if (preg_match('/^\s*(\d+)\s+(\d+\.\d+\.\d+\.\d+)/', $l, $m)) {
|
||||
$rows[] = ['ip'=>$m[2], 'count'=>(int)$m[1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,10 +58,11 @@
|
|||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button wire:click="refresh"
|
||||
<button wire:click="refresh" wire:loading.attr="disabled"
|
||||
class="px-3 py-1.5 text-[12px] rounded-lg bg-white/5 border border-white/10 hover:bg-white/10">
|
||||
<i class="ph ph-arrows-clockwise text-[13px]"></i>
|
||||
Neu prüfen
|
||||
<span wire:loading.remove>Neu prüfen</span>
|
||||
<span wire:loading>prüfe…</span>
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue