首页 > 解决方案 > 检查一个 IP 是否存在于多个 CIDR 范围内

问题描述

我正在构建一个基本的 WAF,并且可以访问多个 CIDR 范围的不良访问者。

我的实现如下所示:

$badIPRanges = [
    '1.2.220.142/31',
    '1.2.220.144/29',
    '1.2.220.152/30',
];

function isBlackListed(string $ip, array $ipRanges): bool {
    foreach ($ipRanges as $ipRange) {
        if (ipInRange($ip, $ipRange)) {
            return true;
        }
    }
    return false;
}

function ipInRange(string $ip, string $ipRange): bool {
    [$net, $mask] = explode('/', $ipRange);
    $ip_net = ip2long($net);
    $ip_mask = ~((1 << (32 - $mask)) - 1);
    $ip_ip = ip2long($ip);
    $ip_ip_net = $ip_ip & $ip_mask;
    return ($ip_ip_net == $ip_net);
}

var_dump(isBlackListed('1.2.220.145', $badIPRanges) ? 'Yes' : 'No');

我预计1.2.220.145不会在多个 CIDR 范围内,但显然不是。我正在Yes从上面的测试代码中恢复过来。

难道我做错了什么?或者这是有效的?最初的实现取自这里

使用https://tehnoblog.org/ip-tools/ip-address-in-cidr-range/我验证了1.2.220.145它在1.2.220.144/29CIDR 块中,这是否意味着 CIDR 块在我的列表1.2.220.142/31中是多余的?$badIPRanges

标签: phpipcidr

解决方案


除非您已经深入内化了该格式,否则您很少会看到点分四边形符号并且知道子网划分是什么,而不是 8 的倍数。

这些网络的二进制表示是:

1.2.220.142 31 00000001 00000010 11011100 10001110
1.2.220.144 29 00000001 00000010 11011100 10010000
1.2.220.152 30 00000001 00000010 11011100 10011000

1.2.220.142/31与其他两个完全不同,并且没有重叠。


推荐阅读