我有一个 Laravel 应用程序,我在其中为 API 路由创建了中间件,以根据 .env 文件中存储的 IP 地址白名单检查请求 IP(我想将 IP 存储在数据库表中,但不确定最佳方法存储带有子网的 IP 地址,但这是另一天的问题)。
我现在需要将带有子网掩码的IP添加到白名单中。如何修改下面的代码来检查请求IP是否在子网范围内?
$requestIP = '12.23.34.56';
// Original array of IP addresses
// $whitelist = collect([
// '127.0.0.1',
// ]);
$whitelist = collect([
'127.0.0.1',
'12.23.34.0/27'
]);
if ($whitelist->contains($request->ip())) {
return $next($request);
}
abort(response('Unauthorized IP', 403));
这里有一个解决方案,但仅适用于 IPv4,且仅适用于 64 位系统。
<?PHP
$testlist = [
'127.0.0.1',
'127.0.0.2',
'12.23.34.1',
'12.23.34.56',
'12.23.35.56',
];
$whitelist = [
'127.0.0.1',
'12.23.34.0/27',
];
function checkip ( $ip )
{
global $whitelist;
//--- convert whilelist to a data structure for faster checks
static $reflist = NULL;
if (!isset($reflist))
{
$reflist = [];
foreach ( $whitelist as $allow )
{
$p = strpos($allow,'/');
if ( $p === false )
{
$num = ip2long($allow);
$bits = 32;
}
else
{
$num = ip2long(substr($allow,0,$p));
$bits = intval(substr($allow,$p+1));
}
if ( $num !== false && $bits > 0 && $bits <= 32 )
{
$mask = ( 0xffffffff<<(32-$bits) ) & 0xffffffff;
printf("%08x %08x\n",$num&$mask,$mask);
$reflist[] = [$num&$mask,$mask];
}
}
}
//---check ipv4
$ip = ip2long($ip);
if ( $ip !== false )
{
foreach ( $reflist as $d )
if ( $d[0] == ( $ip & $d[1] ))
return true;
}
return false;
}
foreach ( $testlist as $ip )
printf("%15s : %d\n",$ip,checkip($ip));
?>