我在 PHP 中有一个 ACL 实现,它采用一组 IPv4 网络并检查地址是否与其中一个匹配,工作原理如下:
$acl = array("192.168.0.0/24", "10.6.0.0/16");
if (address_in_range($_SERVER['REMOTE_ADDR'], $acl) {
// Allow the action...
}
我制作的address_in_range()函数适用于IPv4,我是这样做的:
list($subnet, $mask) = explode('/', $cidr);
if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1) ) == ip2long($subnet)) {
return true;
}
但是,我还需要它使用 IPv6 地址,因此我可以向我的函数提供一组混合的 IPv4 和 IPv6 范围,如下所示:
$acl = array("192.168.0.0/24", "10.6.0.0/16", "2a01:1098:15::/48");
检查的IP可以是IPv4或IPv6。
最佳答案
我最终编写了这个函数来完成这项工作:
/**
* Check if an IP address matches an entry in an access control list (ACL)
* Returns true if match, false otherwise (including if $ip is not a valid IP
* address). Works with both IPv4 and IPv6 addresses.
*
* Example: check_acl("10.6.1.16", array("10.6.0.0/16","2a01:fe8:95::/48"));
* @param string $ip IP address to check
* @param array $acl Array of CIDR-notation IP addresses
* @return boolean
*/
function check_acl($ip, $acl) {
$ipb = inet_pton($ip);
$iplen = strlen($ipb);
if (strlen($ipb) < 4) {
// Invalid IP address
return false;
}
foreach ($acl as $cidr) {
$ar = explode('/',$cidr);
$ip1 = $ar[0];
$ip1b = inet_pton($ip1);
$ip1len = strlen($ip1b);
if ($ip1len != $iplen) {
// Different type
continue;
}
if (count($ar)>1) {
$bits=(int)($ar[1]);
} else {
$bits = $iplen * 8;
}
for ($c=0; $bits>0; $c++) {
$bytemask = ($bits < 8) ? 0xff ^ ((1 << (8-$bits))-1) : 0xff;
if (((ord($ipb[$c]) ^ ord($ip1b[$c])) & $bytemask) != 0)
continue 2;
$bits-=8;
}
return true;
}
return false;
}
关于php - 如何在 PHP 中检查 IPv6 地址是否在特定网络中(用于 ACL 实现),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49365018/