/dev/null')) ?: ''; if ($bin === '') { $this->available = false; $this->permDenied = false; $this->activeBans = 0; $this->jails = []; $this->topIps = []; return; } // ping → prüft zugleich Rechte (liefert Fehlertext, wenn Socket gesperrt) [$ok, $raw] = $this->f2b('ping'); // ok==true wenn "pong" if (!$ok && stripos($raw, 'permission denied') !== false) { $this->available = true; $this->permDenied = true; $this->activeBans = 0; $this->jails = []; $this->topIps = $this->collectTopIps(); return; } // Jails [, $status] = $this->f2b('status'); $jailsLn = $this->firstMatch('/Jail list:\s*(.+)$/mi', $status); $jails = $jailsLn ? array_filter(array_map('trim', preg_split('/\s*,\s*/', $jailsLn))) : []; $total = 0; $rows = []; foreach ($jails as $j) { [, $s] = $this->f2b('status '.escapeshellarg($j)); $banned = (int) ($this->firstMatch('/Currently banned:\s+(\d+)/i', $s) ?: 0); $ipList = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: ''; $ips = $ipList !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipList)))) : []; $rows[] = ['name'=>$j,'banned'=>$banned,'ips'=>array_slice($ips, 0, 8)]; $total += $banned; } $this->available = true; $this->permDenied = false; $this->activeBans = $total; $this->jails = $rows; $this->topIps = $this->collectTopIps(); } /** führt fail2ban-client aus; mit sudo-Fallback; 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); $ok = stripos($out, 'Status') !== false || stripos($out, 'Jail list') !== false || stripos($out, 'pong') !== false; return [$ok, $out]; } private function firstMatch(string $pattern, string $haystack): ?string { return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null; } private function collectTopIps(): array { // … (deine vorhandene Methode aus meiner letzten Antwort – passt) // lässt du unverändert. } }