mailwolt/app/Support/NetProbe.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;
}
}