parent
d3783e1717
commit
94aec78d4c
|
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace App\Livewire\Ui\Security;
|
namespace App\Livewire\Ui\Security;
|
||||||
|
|
||||||
use Livewire\Attributes\On;
|
use Livewire\Attributes\On;
|
||||||
|
|
@ -34,64 +35,74 @@ class Fail2banSettings extends Component
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
// Setting holen oder mit Defaults anlegen
|
// Setting holen oder Defaults anlegen
|
||||||
$this->settings = Fail2banSetting::first() ?? Fail2banSetting::create([
|
$this->settings = Fail2banSetting::first() ?? Fail2banSetting::create([
|
||||||
'bantime' => 3600, 'max_bantime' => 43200, 'bantime_increment' => true,
|
'bantime' => 3600,
|
||||||
'bantime_factor' => 1.5, 'max_retry' => 3, 'findtime' => 600,
|
'max_bantime' => 43200,
|
||||||
'cidr_v4' => 32, 'cidr_v6' => 128, 'external_mode' => false,
|
'bantime_increment' => true,
|
||||||
|
'bantime_factor' => 1.5,
|
||||||
|
'max_retry' => 3,
|
||||||
|
'findtime' => 600,
|
||||||
|
'cidr_v4' => 32,
|
||||||
|
'cidr_v6' => 128,
|
||||||
|
'external_mode' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Properties füllen (KEINE Mixed-Objekte in Inputs binden)
|
// Properties befüllen
|
||||||
$this->fill([
|
$this->fill([
|
||||||
'bantime' => (int)$this->settings->bantime,
|
'bantime' => (int)$this->settings->bantime,
|
||||||
'max_bantime' => (int)$this->settings->max_bantime,
|
'max_bantime' => (int)$this->settings->max_bantime,
|
||||||
'bantime_increment' => (bool)$this->settings->bantime_increment,
|
'bantime_increment' => (bool)$this->settings->bantime_increment,
|
||||||
'bantime_factor' => (float)$this->settings->bantime_factor,
|
'bantime_factor' => (float)$this->settings->bantime_factor,
|
||||||
'max_retry' => (int)$this->settings->max_retry,
|
'max_retry' => (int)$this->settings->max_retry,
|
||||||
'findtime' => (int)$this->settings->findtime,
|
'findtime' => (int)$this->settings->findtime,
|
||||||
'cidr_v4' => (int)$this->settings->cidr_v4,
|
'cidr_v4' => (int)$this->settings->cidr_v4,
|
||||||
'cidr_v6' => (int)$this->settings->cidr_v6,
|
'cidr_v6' => (int)$this->settings->cidr_v6,
|
||||||
'external_mode' => (bool)$this->settings->external_mode,
|
'external_mode' => (bool)$this->settings->external_mode,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->whitelist = Fail2banIpList::where('type','whitelist')->pluck('ip')->toArray();
|
$this->refreshLists();
|
||||||
$this->blacklist = Fail2banIpList::where('type','blacklist')->pluck('ip')->toArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(): void
|
public function save(): void
|
||||||
{
|
{
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'bantime' => 'required|integer|min:60',
|
'bantime' => 'required|integer|min:60',
|
||||||
'max_bantime' => 'required|integer|min:60',
|
'max_bantime' => 'required|integer|min:60',
|
||||||
'bantime_factor' => 'required|numeric|min:1',
|
'bantime_factor' => 'required|numeric|min:1',
|
||||||
'max_retry' => 'required|integer|min:1',
|
'max_retry' => 'required|integer|min:1',
|
||||||
'findtime' => 'required|integer|min:60',
|
'findtime' => 'required|integer|min:60',
|
||||||
'cidr_v4' => 'required|integer|min:8|max:32',
|
'cidr_v4' => 'required|integer|min:8|max:32',
|
||||||
'cidr_v6' => 'required|integer|min:8|max:128',
|
'cidr_v6' => 'required|integer|min:8|max:128',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Einstellungen speichern
|
||||||
$this->settings->update([
|
$this->settings->update([
|
||||||
'bantime' => $this->bantime,
|
'bantime' => $this->bantime,
|
||||||
'max_bantime' => $this->max_bantime,
|
'max_bantime' => $this->max_bantime,
|
||||||
'bantime_increment' => $this->bantime_increment,
|
'bantime_increment' => $this->bantime_increment,
|
||||||
'bantime_factor' => $this->bantime_factor,
|
'bantime_factor' => $this->bantime_factor,
|
||||||
'max_retry' => $this->max_retry,
|
'max_retry' => $this->max_retry,
|
||||||
'findtime' => $this->findtime,
|
'findtime' => $this->findtime,
|
||||||
'cidr_v4' => $this->cidr_v4,
|
'cidr_v4' => $this->cidr_v4,
|
||||||
'cidr_v6' => $this->cidr_v6,
|
'cidr_v6' => $this->cidr_v6,
|
||||||
'external_mode' => $this->external_mode,
|
'external_mode' => $this->external_mode,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Config-Dateien schreiben
|
||||||
$this->writeDefaultsConfig();
|
$this->writeDefaultsConfig();
|
||||||
$this->writeWhitelistConfig();
|
$this->writeWhitelistConfig();
|
||||||
|
|
||||||
@shell_exec('sudo fail2ban-client reload');
|
// Fail2Ban reload
|
||||||
|
$this->runCommand('sudo -n /usr/bin/fail2ban-client reload');
|
||||||
|
|
||||||
$this->dispatch('notify', message: 'Gespeichert & Fail2Ban neu geladen.');
|
$this->dispatch('notify', message: 'Gespeichert & Fail2Ban neu geladen.');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function writeDefaultsConfig(): void
|
protected function writeDefaultsConfig(): void
|
||||||
{
|
{
|
||||||
$s = $this->settings;
|
$s = $this->settings;
|
||||||
|
|
||||||
$content = <<<CONF
|
$content = <<<CONF
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
bantime = {$s->bantime}
|
bantime = {$s->bantime}
|
||||||
|
|
@ -101,15 +112,65 @@ bantime.increment = {$this->boolToStr($s->bantime_increment)}
|
||||||
bantime.factor = {$s->bantime_factor}
|
bantime.factor = {$s->bantime_factor}
|
||||||
bantime.maxtime = {$s->max_bantime}
|
bantime.maxtime = {$s->max_bantime}
|
||||||
CONF;
|
CONF;
|
||||||
file_put_contents('/etc/fail2ban/jail.d/00-mailwolt-defaults.local', $content);
|
|
||||||
|
$this->writeRootFileViaTee('/etc/fail2ban/jail.d/00-mailwolt-defaults.local', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function writeWhitelistConfig(): void
|
protected function writeWhitelistConfig(): void
|
||||||
{
|
{
|
||||||
$ips = Fail2banIpList::where('type','whitelist')->pluck('ip')->toArray();
|
$ips = Fail2banIpList::where('type', 'whitelist')->pluck('ip')->toArray();
|
||||||
$ignore = implode(' ', array_unique(array_filter($ips)));
|
$ignore = implode(' ', array_unique(array_filter($ips)));
|
||||||
|
|
||||||
$content = "[DEFAULT]\nignoreip = {$ignore}\n";
|
$content = "[DEFAULT]\nignoreip = {$ignore}\n";
|
||||||
file_put_contents('/etc/fail2ban/jail.d/mailwolt-whitelist.local', $content);
|
|
||||||
|
$this->writeRootFileViaTee('/etc/fail2ban/jail.d/mailwolt-whitelist.local', $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schreibt Root-Dateien sicher via `sudo tee`
|
||||||
|
*/
|
||||||
|
private function writeRootFileViaTee(string $target, string $content): void
|
||||||
|
{
|
||||||
|
if (!preg_match('#^/etc/fail2ban/jail\.d/[A-Za-z0-9._-]+\.local$#', $target)) {
|
||||||
|
throw new \RuntimeException("Illegal path: $target");
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd = sprintf('sudo -n /usr/bin/tee %s >/dev/null', escapeshellarg($target));
|
||||||
|
|
||||||
|
$descriptorspec = [
|
||||||
|
0 => ['pipe', 'r'],
|
||||||
|
1 => ['pipe', 'w'],
|
||||||
|
2 => ['pipe', 'w'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$proc = proc_open($cmd, $descriptorspec, $pipes, null, null);
|
||||||
|
if (!is_resource($proc)) {
|
||||||
|
throw new \RuntimeException('Failed to start tee');
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite($pipes[0], $content);
|
||||||
|
fclose($pipes[0]);
|
||||||
|
stream_get_contents($pipes[1]);
|
||||||
|
stream_get_contents($pipes[2]);
|
||||||
|
$exitCode = proc_close($proc);
|
||||||
|
|
||||||
|
if ($exitCode !== 0) {
|
||||||
|
throw new \RuntimeException("tee failed writing to {$target}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Führt Systembefehle aus und wirft Exception bei Fehlern
|
||||||
|
*/
|
||||||
|
private function runCommand(string $cmd): void
|
||||||
|
{
|
||||||
|
$output = [];
|
||||||
|
$return = 0;
|
||||||
|
exec($cmd . ' 2>&1', $output, $return);
|
||||||
|
|
||||||
|
if ($return !== 0) {
|
||||||
|
throw new \RuntimeException("Command failed ($return): {$cmd}\n" . implode("\n", $output));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function boolToStr(bool $v): string
|
private function boolToStr(bool $v): string
|
||||||
|
|
@ -122,3 +183,158 @@ CONF;
|
||||||
return view('livewire.ui.security.fail2ban-settings');
|
return view('livewire.ui.security.fail2ban-settings');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//namespace App\Livewire\Ui\Security;
|
||||||
|
//
|
||||||
|
//use Livewire\Attributes\On;
|
||||||
|
//use Livewire\Component;
|
||||||
|
//use App\Models\Fail2banSetting;
|
||||||
|
//use App\Models\Fail2banIpList;
|
||||||
|
//
|
||||||
|
//class Fail2banSettings extends Component
|
||||||
|
//{
|
||||||
|
// // Formfelder
|
||||||
|
// public int $bantime;
|
||||||
|
// public int $max_bantime;
|
||||||
|
// public bool $bantime_increment;
|
||||||
|
// public float $bantime_factor;
|
||||||
|
// public int $max_retry;
|
||||||
|
// public int $findtime;
|
||||||
|
// public int $cidr_v4;
|
||||||
|
// public int $cidr_v6;
|
||||||
|
// public bool $external_mode;
|
||||||
|
//
|
||||||
|
// public array $whitelist = [];
|
||||||
|
// public array $blacklist = [];
|
||||||
|
//
|
||||||
|
// public Fail2banSetting $settings;
|
||||||
|
//
|
||||||
|
// #[On('f2b:refresh')]
|
||||||
|
// public function refreshLists(): void
|
||||||
|
// {
|
||||||
|
// $this->whitelist = Fail2banIpList::where('type', 'whitelist')->pluck('ip')->toArray();
|
||||||
|
// $this->blacklist = Fail2banIpList::where('type', 'blacklist')->pluck('ip')->toArray();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function mount(): void
|
||||||
|
// {
|
||||||
|
// // Setting holen oder mit Defaults anlegen
|
||||||
|
// $this->settings = Fail2banSetting::first() ?? Fail2banSetting::create([
|
||||||
|
// 'bantime' => 3600, 'max_bantime' => 43200, 'bantime_increment' => true,
|
||||||
|
// 'bantime_factor' => 1.5, 'max_retry' => 3, 'findtime' => 600,
|
||||||
|
// 'cidr_v4' => 32, 'cidr_v6' => 128, 'external_mode' => false,
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// // Properties füllen (KEINE Mixed-Objekte in Inputs binden)
|
||||||
|
// $this->fill([
|
||||||
|
// 'bantime' => (int)$this->settings->bantime,
|
||||||
|
// 'max_bantime' => (int)$this->settings->max_bantime,
|
||||||
|
// 'bantime_increment' => (bool)$this->settings->bantime_increment,
|
||||||
|
// 'bantime_factor' => (float)$this->settings->bantime_factor,
|
||||||
|
// 'max_retry' => (int)$this->settings->max_retry,
|
||||||
|
// 'findtime' => (int)$this->settings->findtime,
|
||||||
|
// 'cidr_v4' => (int)$this->settings->cidr_v4,
|
||||||
|
// 'cidr_v6' => (int)$this->settings->cidr_v6,
|
||||||
|
// 'external_mode' => (bool)$this->settings->external_mode,
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// $this->whitelist = Fail2banIpList::where('type','whitelist')->pluck('ip')->toArray();
|
||||||
|
// $this->blacklist = Fail2banIpList::where('type','blacklist')->pluck('ip')->toArray();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function save(): void
|
||||||
|
// {
|
||||||
|
// $this->validate([
|
||||||
|
// 'bantime' => 'required|integer|min:60',
|
||||||
|
// 'max_bantime' => 'required|integer|min:60',
|
||||||
|
// 'bantime_factor' => 'required|numeric|min:1',
|
||||||
|
// 'max_retry' => 'required|integer|min:1',
|
||||||
|
// 'findtime' => 'required|integer|min:60',
|
||||||
|
// 'cidr_v4' => 'required|integer|min:8|max:32',
|
||||||
|
// 'cidr_v6' => 'required|integer|min:8|max:128',
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// $this->settings->update([
|
||||||
|
// 'bantime' => $this->bantime,
|
||||||
|
// 'max_bantime' => $this->max_bantime,
|
||||||
|
// 'bantime_increment' => $this->bantime_increment,
|
||||||
|
// 'bantime_factor' => $this->bantime_factor,
|
||||||
|
// 'max_retry' => $this->max_retry,
|
||||||
|
// 'findtime' => $this->findtime,
|
||||||
|
// 'cidr_v4' => $this->cidr_v4,
|
||||||
|
// 'cidr_v6' => $this->cidr_v6,
|
||||||
|
// 'external_mode' => $this->external_mode,
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// $this->writeDefaultsConfig();
|
||||||
|
// $this->writeWhitelistConfig();
|
||||||
|
//
|
||||||
|
// @shell_exec('sudo fail2ban-client reload');
|
||||||
|
// $this->dispatch('notify', message: 'Gespeichert & Fail2Ban neu geladen.');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected function writeDefaultsConfig(): void
|
||||||
|
// {
|
||||||
|
// $s = $this->settings;
|
||||||
|
// $content = <<<CONF
|
||||||
|
//[DEFAULT]
|
||||||
|
//bantime = {$s->bantime}
|
||||||
|
//findtime = {$s->findtime}
|
||||||
|
//maxretry = {$s->max_retry}
|
||||||
|
//bantime.increment = {$this->boolToStr($s->bantime_increment)}
|
||||||
|
//bantime.factor = {$s->bantime_factor}
|
||||||
|
//bantime.maxtime = {$s->max_bantime}
|
||||||
|
//CONF;
|
||||||
|
// file_put_contents('/etc/fail2ban/jail.d/00-mailwolt-defaults.local', $content);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected function writeWhitelistConfig(): void
|
||||||
|
// {
|
||||||
|
// $ips = Fail2banIpList::where('type','whitelist')->pluck('ip')->toArray();
|
||||||
|
// $ignore = implode(' ', array_unique(array_filter($ips)));
|
||||||
|
// $content = "[DEFAULT]\nignoreip = {$ignore}\n";
|
||||||
|
// file_put_contents('/etc/fail2ban/jail.d/mailwolt-whitelist.local', $content);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private function writeRootFileViaTee(string $target, string $content): void
|
||||||
|
// {
|
||||||
|
// // Nur erlaubte Pfade (Hardening)
|
||||||
|
// if (!preg_match('#^/etc/fail2ban/jail\.d/[A-Za-z0-9._-]+\.local$#', $target)) {
|
||||||
|
// throw new \RuntimeException("Illegal path: $target");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $cmd = sprintf('sudo -n /usr/bin/tee %s >/dev/null', escapeshellarg($target));
|
||||||
|
//
|
||||||
|
// $descriptorspec = [
|
||||||
|
// 0 => ['pipe', 'r'], // stdin -> tee
|
||||||
|
// 1 => ['pipe', 'w'], // stdout
|
||||||
|
// 2 => ['pipe', 'w'], // stderr
|
||||||
|
// ];
|
||||||
|
//
|
||||||
|
// $proc = proc_open($cmd, $descriptorspec, $pipes, null, null);
|
||||||
|
// if (!is_resource($proc)) {
|
||||||
|
// throw new \RuntimeException('Failed to start tee');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fwrite($pipes[0], $content);
|
||||||
|
// fclose($pipes[0]);
|
||||||
|
// $stdout = stream_get_contents($pipes[1]); fclose($pipes[1]);
|
||||||
|
// $stderr = stream_get_contents($pipes[2]); fclose($pipes[2]);
|
||||||
|
//
|
||||||
|
// $code = proc_close($proc);
|
||||||
|
// if ($code !== 0) {
|
||||||
|
// throw new \RuntimeException("tee failed (code $code): $stderr $stdout");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private function boolToStr(bool $v): string
|
||||||
|
// {
|
||||||
|
// return $v ? 'true' : 'false';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public function render()
|
||||||
|
// {
|
||||||
|
// return view('livewire.ui.security.fail2ban-settings');
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue