Reputation: 899
I have a Laravel app where I have created middleware for an API route to check the request IP against a whitelist of IP addresses stored in the .env file (I would like to store the IPs in a database table but not sure of best way to store the IP addresses with subnet but that's a question for another day).
I now need to add an IP with subnet mask to the whitelist. How can I modify the code below to check if the request IP is within the subnet range?
$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));
Upvotes: 0
Views: 67
Reputation: 3570
Here is a solution, but only for IPv4. I'm note sure if this code runs at 32-bit systems.
<?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));
?>
Change && $bits > 0 &&
to && $bits >= 0 &&
if you want to allow 0.0.0.0/0
for all ipv4 addresses.
Upvotes: 1