205 lines
6.1 KiB
PHP
205 lines
6.1 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Livewire\Ui\Security;
|
||
|
||
use Livewire\Component;
|
||
use Illuminate\Support\Facades\Cache;
|
||
|
||
class RblCard extends Component
|
||
{
|
||
public string $ip = '–';
|
||
public int $hits = 0;
|
||
public array $lists = [];
|
||
|
||
public ?string $ipv4 = null;
|
||
public ?string $ipv6 = null;
|
||
|
||
public function mount(): void
|
||
{
|
||
$this->load();
|
||
}
|
||
|
||
public function render()
|
||
{
|
||
return view('livewire.ui.security.rbl-card');
|
||
}
|
||
|
||
public function refresh(): void
|
||
{
|
||
Cache::forget('dash.rbl');
|
||
$this->load(true);
|
||
}
|
||
|
||
protected function load(bool $force = false): void
|
||
{
|
||
// 1) IPv4/IPv6 bevorzugt aus /etc/mailwolt/installer.env
|
||
[$ip4, $ip6] = $this->resolvePublicIpsFromInstallerEnv();
|
||
|
||
// 2) Fallback auf .env
|
||
$this->ipv4 = $ip4 ?: trim((string) env('SERVER_PUBLIC_IPV4', '')) ?: '–';
|
||
$this->ipv6 = $ip6 ?: trim((string) env('SERVER_PUBLIC_IPV6', '')) ?: '–';
|
||
|
||
// 3) RBL-Ermittlung (cached)
|
||
$data = Cache::remember('dash.rbl', $force ? 1 : 21600, function () {
|
||
// bevorzugt eine valide IPv4 für den RBL-Check
|
||
$candidate = $this->validIPv4($this->ipv4 ?? '') ? $this->ipv4 : null;
|
||
|
||
if (!$candidate) {
|
||
$fromFile = @file_get_contents('/etc/mailwolt/public_ip') ?: '';
|
||
$fromFile = trim($fromFile);
|
||
if ($this->validIPv4($fromFile)) {
|
||
$candidate = $fromFile;
|
||
}
|
||
}
|
||
|
||
if (!$candidate) {
|
||
// letzter Fallback – kann auf Hardened-Systemen geblockt sein
|
||
$curl = @shell_exec("curl -fsS --max-time 2 ifconfig.me 2>/dev/null") ?: '';
|
||
$curl = trim($curl);
|
||
if ($this->validIPv4($curl)) {
|
||
$candidate = $curl;
|
||
}
|
||
}
|
||
|
||
$ip = $candidate ?: '0.0.0.0';
|
||
$lists = $this->queryRblLists($ip);
|
||
|
||
return ['ip' => $ip, 'hits' => count($lists), 'lists' => $lists];
|
||
});
|
||
|
||
// 4) Werte ins Component-State
|
||
foreach ($data as $k => $v) {
|
||
$this->$k = $v;
|
||
}
|
||
}
|
||
|
||
/** Bevorzugt Installer-ENV; gibt [ipv4, ipv6] zurück oder [null, null]. */
|
||
private function resolvePublicIpsFromInstallerEnv(): array
|
||
{
|
||
$file = '/etc/mailwolt/installer.env';
|
||
if (!is_readable($file)) {
|
||
return [null, null];
|
||
}
|
||
|
||
$ipv4 = null;
|
||
$ipv6 = null;
|
||
|
||
$lines = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
|
||
foreach ($lines as $line) {
|
||
// Kommentare überspringen
|
||
if (preg_match('/^\s*#/', $line)) {
|
||
continue;
|
||
}
|
||
// KEY=VALUE (VALUE evtl. in "..." oder '...')
|
||
if (!str_contains($line, '=')) {
|
||
continue;
|
||
}
|
||
[$k, $v] = array_map('trim', explode('=', $line, 2));
|
||
$v = trim($v, " \t\n\r\0\x0B\"'");
|
||
|
||
if ($k === 'SERVER_PUBLIC_IPV4' && $this->validIPv4($v)) {
|
||
$ipv4 = $v;
|
||
} elseif ($k === 'SERVER_PUBLIC_IPV6' && $this->validIPv6($v)) {
|
||
$ipv6 = $v;
|
||
}
|
||
}
|
||
|
||
return [$ipv4, $ipv6];
|
||
}
|
||
|
||
private function validIPv4(?string $ip): bool
|
||
{
|
||
return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
||
}
|
||
|
||
private function validIPv6(?string $ip): bool
|
||
{
|
||
return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
|
||
}
|
||
|
||
/**
|
||
* Prüft die IP gegen ein paar gängige RBLs.
|
||
* Nutzt PHP-DNS (checkdnsrr), keine externen Tools.
|
||
*
|
||
* @return array<string> gelistete RBL-Zonen
|
||
*/
|
||
private function queryRblLists(string $ip): array
|
||
{
|
||
// Nur IPv4 prüfen (die meisten Listen hier sind v4)
|
||
if (!$this->validIPv4($ip)) {
|
||
return [];
|
||
}
|
||
|
||
$rev = implode('.', array_reverse(explode('.', $ip)));
|
||
$sources = [
|
||
'zen.spamhaus.org',
|
||
'bl.spamcop.net',
|
||
'dnsbl.sorbs.net',
|
||
'b.barracudacentral.org',
|
||
];
|
||
|
||
$listed = [];
|
||
foreach ($sources as $zone) {
|
||
$qname = "{$rev}.{$zone}";
|
||
// A-Record oder TXT deuten auf Listing hin
|
||
if (@checkdnsrr($qname . '.', 'A') || @checkdnsrr($qname . '.', 'TXT')) {
|
||
$listed[] = $zone;
|
||
}
|
||
}
|
||
|
||
return $listed;
|
||
}
|
||
}
|
||
//
|
||
//namespace App\Livewire\Ui\Security;
|
||
//
|
||
//use Livewire\Component;
|
||
//use Illuminate\Support\Facades\Cache;
|
||
//
|
||
//class RblCard extends Component
|
||
//{
|
||
// public string $ip = '–';
|
||
// public int $hits = 0;
|
||
// public array $lists = [];
|
||
//
|
||
// public ?string $ipv4 = null;
|
||
// public ?string $ipv6 = null;
|
||
//
|
||
//
|
||
// public function mount(): void { $this->load(); }
|
||
// public function render() { return view('livewire.ui.security.rbl-card'); }
|
||
// public function refresh(): void { $this->load(true); }
|
||
//
|
||
// protected function load(bool $force=false): void
|
||
// {
|
||
// $this->ipv4 = trim(env('SERVER_PUBLIC_IPV4')) ?: '–';
|
||
// $this->ipv6 = trim(env('SERVER_PUBLIC_IPV6')) ?: '–';
|
||
//
|
||
// $data = Cache::remember('dash.rbl', $force ? 1 : 21600, function () {
|
||
// $ip = trim(@file_get_contents('/etc/mailwolt/public_ip') ?: '');
|
||
// if ($ip === '') $ip = trim(@shell_exec("curl -fsS --max-time 2 ifconfig.me 2>/dev/null") ?? '');
|
||
// if (!preg_match('/^\d+\.\d+\.\d+\.\d+$/', $ip)) $ip = '0.0.0.0';
|
||
//
|
||
// $rev = implode('.', array_reverse(explode('.', $ip)));
|
||
// $sources = [
|
||
// 'zen.spamhaus.org',
|
||
// 'bl.spamcop.net',
|
||
// 'dnsbl.sorbs.net',
|
||
// 'b.barracudacentral.org',
|
||
// ];
|
||
//
|
||
// $lists = [];
|
||
// foreach ($sources as $s) {
|
||
// $q = "$rev.$s";
|
||
// $res = trim(@shell_exec("dig +short ".escapeshellarg($q)." A 2>/dev/null") ?? '');
|
||
// if ($res !== '') $lists[] = $s;
|
||
// }
|
||
//
|
||
// return ['ip'=>$ip, 'hits'=>count($lists), 'lists'=>$lists];
|
||
// });
|
||
//
|
||
// foreach ($data as $k=>$v) $this->$k = $v;
|
||
// }
|
||
//}
|