86 lines
2.7 KiB
PHP
86 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace App\Support;
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
class NetProbe
|
|
{
|
|
public static function resolve(bool $force = false): array
|
|
{
|
|
return [
|
|
'ipv4' => self::getIPv4($force),
|
|
'ipv6' => self::getIPv6($force),
|
|
];
|
|
}
|
|
|
|
public static function getIPv4(bool $force = false): ?string
|
|
{
|
|
// 1) ENV zuerst
|
|
$env = trim((string) env('SERVER_PUBLIC_IPV4', ''));
|
|
if ($env !== '' && filter_var($env, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
|
return $env;
|
|
}
|
|
|
|
// 2) Cache
|
|
if (!$force) {
|
|
$c = Cache::get('netprobe:ipv4');
|
|
if ($c) return $c === 'none' ? null : $c;
|
|
}
|
|
|
|
// 3) Probe (einmalig)
|
|
$ip = self::probeIPv4();
|
|
Cache::put('netprobe:ipv4', $ip ?: 'none', now()->addDay());
|
|
|
|
return $ip;
|
|
}
|
|
|
|
public static function getIPv6(bool $force = false): ?string
|
|
{
|
|
// 1) ENV zuerst
|
|
$env = trim((string) env('SERVER_PUBLIC_IPV6', ''));
|
|
if ($env !== '' && filter_var($env, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
return $env;
|
|
}
|
|
|
|
// 2) Cache mit Sentinel „none“ (verhindert Endlossuche)
|
|
if (!$force) {
|
|
$c = Cache::get('netprobe:ipv6');
|
|
if ($c) return $c === 'none' ? null : $c;
|
|
}
|
|
|
|
// 3) Probe (einmalig)
|
|
$ip = self::probeIPv6();
|
|
Cache::put('netprobe:ipv6', $ip ?: 'none', now()->addDay());
|
|
|
|
return $ip;
|
|
}
|
|
|
|
// — intern —
|
|
|
|
protected static function probeIPv4(): ?string
|
|
{
|
|
$out = @shell_exec("ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'");
|
|
$ip = trim((string) $out);
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) return $ip;
|
|
|
|
$ip = trim($_SERVER['SERVER_ADDR'] ?? '');
|
|
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? $ip : null;
|
|
}
|
|
|
|
protected static function probeIPv6(): ?string
|
|
{
|
|
// Variante 1: „Standard“-Weg über Routing
|
|
$out = @shell_exec("ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if(\$i==\"src\"){print \$(i+1); exit}}'");
|
|
$ip = trim((string) $out);
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return $ip;
|
|
|
|
// Variante 2: irgendeine globale v6 vom Interface nehmen (keine ::1, keine link-local fe80:)
|
|
$out = @shell_exec("ip -6 addr show scope global 2>/dev/null | awk '/inet6/ && $2 !~ /::1/ && $2 !~ /^fe80:/ {print $2; exit}'");
|
|
$ip = trim((string) $out);
|
|
if ($ip !== '') $ip = strtok($ip, '/'); // Prefix entfernen
|
|
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $ip : null;
|
|
}
|
|
|
|
}
|