Is there a way (or function/class) to get the list of IP addresses from a CIDR notation?
For example, I have 73.35.143.32/27 CIDR and want to get the list of all IP\
Hej. I also needed this function and I edit 1 other to return me list of all IP addresses from range. This will return list of IP addresses from CIDR Notation. Enjoy it ;)
<?php
$ip_addr_cidr = "192.256.0.0/16";
$ip_arr = explode('/', $ip_addr_cidr);
$bin = '';
for($i=1;$i<=32;$i++) {
$bin .= $ip_arr[1] >= $i ? '1' : '0';
}
$ip_arr[1] = bindec($bin);
$ip = ip2long($ip_arr[0]);
$nm = ip2long($ip_arr[1]);
$nw = ($ip & $nm);
$bc = $nw | (~$nm);
echo "Number of Hosts: " . ($bc - $nw - 1) . "<br/>";
echo "Host Range: " . long2ip($nw + 1) . " -> " . long2ip($bc - 1) . "<br/>". "<br/>";
for($zm=1;($nw + $zm)<=($bc - 1);$zm++)
{
echo long2ip($nw + $zm). "<br/>";
}
?>
Highly recommend this PHP Lib: https://github.com/S1lentium/IPTools
It can manipulate network easily with many functions.
e.g. Iterate over Network IP adresses:
$network = Network::parse('192.168.1.0/24');
foreach($network as $ip) {
echo (string)$ip . '<br>';
}
// output:
192.168.1.0
...
192.168.1.255
this returns an array of ips:
function get_list_ip($ip_addr_cidr){
$ip_arr = explode("/", $ip_addr_cidr);
$bin = "";
for($i=1;$i<=32;$i++) {
$bin .= $ip_arr[1] >= $i ? '1' : '0';
}
$ip_arr[1] = bindec($bin);
$ip = ip2long($ip_arr[0]);
$nm = $ip_arr[1];
$nw = ($ip & $nm);
$bc = $nw | ~$nm;
$bc_long = ip2long(long2ip($bc));
for($zm=1;($nw + $zm)<=($bc_long - 1);$zm++)
{
$ret[]=long2ip($nw + $zm);
}
return $ret;
}
Fixed version of Kosmonaft script:
function get_list_ip($ip_addr_cidr){
$ip_arr = explode("/", $ip_addr_cidr);
$bin = "";
for($i=1;$i<=32;$i++) {
$bin .= $ip_arr[1] >= $i ? '1' : '0';
}
$ip_arr[1] = bindec($bin);
$ip = ip2long($ip_arr[0]);
$nm = $ip_arr[1];
$nw = ($ip & $nm);
$bc = $nw | ~$nm;
$bc_long = ip2long(long2ip($bc));
echo "Number of Hosts: " . ($bc_long - $nw - 1) . "<br/>";
echo "Host Range: " . long2ip($nw + 1) . " -> " . long2ip($bc - 1) . "<br/>". "<br/>";
for($zm=1;($nw + $zm)<=($bc_long - 1);$zm++)
{
echo long2ip($nw + $zm). "<br/>";
}
}
I come up with a better idea
$ip_from= long2ip(ip2long($ip)& (-1<<(32-$net_mask)));
$ip_to= long2ip(ip2long($ip)| (~(-1<<(32-$net_mask))));
P.S:$ip is a ipv4 address like 60.12.34.5;$net_mask is a int net mask like 25;
it's very fast because of the bit shift operation
I had some problems with the previous versions, various PHP errors like undefined offset etc.
I found what I think is a better way to do it without the errors as detailed below.
This takes IPV4 CIDR notation IP addresses and can be used to get the start/end IP addresses of the CIDR range or count the total number of IP addresses in a database of IP addresses.
$count = 0;
$result = $sia_db_con->query("SELECT `ip_address` FROM `ip4` WHERE `ip_ban_active`='True' ORDER BY ip4.added ASC");
while ($row = $result->fetch_array()) {
$pos = strpos($row[0], "/");
$ip_arr = [0 => substr($row[0], 0, $pos), 1 => substr($row[0], $pos+1)];
$start = cidr2ip($ip_arr)[0];
$end = cidr2ip($ip_arr)[1];
$count = $count + (ip2long($end) - ip2long($start)) + 1;
}
unset($result, $row, $pos, $ip_arr, $start, $end, $range);
function cidr2ip($cidr) {
$start = ip2long($cidr[0]);
$nm = $cidr[1];
$num = pow(2, 32 - $nm);
$end = $start + $num - 1;
$range = [0 => $cidr[0], 1 => long2ip($end)];
unset($start, $nm, $num, $end);
return $range;
}
The secret here is the way in which I create the $ip_arr variable. Rather than using PHP explode, I set the array dimensions manually for each IP address. This is of course a database version of the code and cycles through all IP addresses in the database which meet the search criteria.