IPv6-tuki IP-rajoitukseen

Vaihdettu ip2long() -> inet_pton() joka tukee sekä IPv4 että IPv6.
CIDR-alueet toimivat molemmilla (esim. 2001:db8::/32).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 08:54:40 +02:00
parent 2b4591c49f
commit 1dc04326aa

31
api.php
View File

@@ -140,29 +140,36 @@ function getClientIp(): string {
/**
* Tarkista onko IP sallittujen listalla.
* Tyhjä lista = ei rajoitusta (kaikki sallittu).
* Tukee yksittäisiä IP-osoitteita ja CIDR-alueita (esim. 192.168.1.0/24).
* Tukee IPv4 ja IPv6, yksittäisiä osoitteita ja CIDR-alueita.
*/
function isIpAllowed(string $ip, string $allowedIps): bool {
$allowedIps = trim($allowedIps);
if ($allowedIps === '' || strtolower($allowedIps) === 'kaikki') return true; // ei rajoitusta
if ($allowedIps === '' || strtolower($allowedIps) === 'kaikki') return true;
$entries = preg_split('/[\s,]+/', $allowedIps, -1, PREG_SPLIT_NO_EMPTY);
$ipLong = ip2long($ip);
if ($ipLong === false) return false;
$ipBin = @inet_pton($ip);
if ($ipBin === false) return false;
foreach ($entries as $entry) {
$entry = trim($entry);
if ($entry === '') continue;
if (strpos($entry, '/') !== false) {
// CIDR-alue (esim. 192.168.1.0/24)
// CIDR-alue (IPv4 tai IPv6)
[$subnet, $bits] = explode('/', $entry, 2);
$bits = (int)$bits;
if ($bits < 0 || $bits > 32) continue;
$subnetLong = ip2long($subnet);
if ($subnetLong === false) continue;
$mask = $bits === 0 ? 0 : (~0 << (32 - $bits));
if (($ipLong & $mask) === ($subnetLong & $mask)) return true;
$subnetBin = @inet_pton($subnet);
if ($subnetBin === false) continue;
// IPv4 = 4 tavua, IPv6 = 16 tavua — pitää olla sama perhe
if (strlen($ipBin) !== strlen($subnetBin)) continue;
$maxBits = strlen($ipBin) * 8;
if ($bits < 0 || $bits > $maxBits) continue;
// Rakenna bittimask
$mask = str_repeat("\xff", intdiv($bits, 8));
if ($bits % 8) $mask .= chr(0xff << (8 - ($bits % 8)));
$mask = str_pad($mask, strlen($ipBin), "\x00");
if (($ipBin & $mask) === ($subnetBin & $mask)) return true;
} else {
// Yksittäinen IP
if (ip2long($entry) === $ipLong) return true;
// Yksittäinen IP (IPv4 tai IPv6)
$entryBin = @inet_pton($entry);
if ($entryBin !== false && $ipBin === $entryBin) return true;
}
}
return false;