Dealing with IP range in PHP/MySQL
Published the Saturday, 2 November 2024 at 04:00
The goal is to process some CIDR blocks to tighten a webservice security.
First let's see how to compute the first and last address of an IP range with just the block base IP and mask:
$range = ['127.0.0.1', 8];
function rangeBegin($range) {
return $range[0];
}
function rangeEnd($range) {
return long2ip(ip2long($range[0]) | ((1 << (32 - $range[1])) - 1));
}
How to detect if an IP is present in a CIDR block:
$ip = '127.0.0.1';
$range = ['127.0.0.1', 8];
function ipInRange($ip, $range) {
if (ip2long($range[0]) <= ip2long($ip) && ip2long($ip) <= (ip2long($range[0]) | ((1 << (32 - $range[1])) - 1))) {
return true;
}
return false;
}
As a first bonus, how to retrieve amazon IP ranges:
function fetchAmazonRange() {
//Init array
$amazonRanges = [];
$ctx = stream_context_create(
[
'http' => [
'method' => 'GET',
'max_redirects' => 0,
'timeout' => 5,
'ignore_errors' => false,
'header' => [
'Connection: close',
'Accept: application/json'
]
]
]
];
//Fetch json
if (($json = file_get_contents('https://ip-ranges.amazonaws.com/ip-ranges.json', false, $ctx)) === false) {
return null;
}
//Decode it
if (($json = json_decode($json)) === null || empty($json->prefixes)) {
return false;
}
//Deal with prefixes
foreach($json->prefixes as $range) {
//Skip ipv6 and invalid ranges
if (empty($range->ip_prefix)||!preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/', $range->ip_prefix, $matche
s)) {
continue;
}
//Remove whole match
array_shift($matches);
//Add ip and mask
$amazonRanges[] = $matches;
}
//Send back result
return $amazonRanges;
}
Microsoft Azure IP ranges urls:
- https://www.microsoft.com/en-us/download/details.aspx?id=41653
- https://msdn.microsoft.com/library/mt757330.aspx
Google IP ranges urls: