php - 如何在 PHP 中检查 IPv6 地址是否在特定网络中(用于 ACL 实现)

标签 php ipv6

我在 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/

相关文章:

php - 从php中的Ajax调用获取2个变量

php - 有什么办法可以将屏幕内容打印到网页上吗?

mysql - 在 LOAD DATA LOCAL INFILE 中使用 INET6_ATON 时返回 null

php - 将数据存储在 javascript 数组中以供进一步使用

php - 如何重命名 Symfony 3/Doctrine 中的表?

c - ipv6组播接收

c - 如何在 C 中将 IPv6 字符串转换为无符号字符数组

ios - 检查网络接口(interface)ip版本ios

将对等方的 IPv6 地址与本地主机进行比较

php - self 加入并仅在一个表/一侧忽略空值