Get IP range by CIDR notation

Posted by Gerben Jacobs on November 21, 2012 in tech, php

I wanted to get the IPv4 range of a WHOIS record provided by LACNIC, because unlike other RIRs they don't supply you with the range, but with just a CIDR notation.

To make matters worse, they give 'incomplete' net numbers. The only working "CIDR to IP range" function I could find didn't accept it, so I had to sprinkle some magic.

<?php
$ipdata = explode('/', ltrim($incomplete_cidr_notation, '0'));
$dotcount = substr_count($ipdata[0], '.');
if ($dotcount != 3) {
    $ipdata[0] .= str_repeat('.0', (3-$dotcount));
}
$finalip = sprintf('%s/%s', $ipdata[0], $ipdata[1]);
$range = cidr_conv($finalip);
?>

The final cidr_conv() is written by someone unknown in 2003 and can be found in the PHP.net comments of the Network functions page.

<?php
function cidr_conv($cidr_address) {
    $first = substr($cidr_address, 0, strpos($cidr_address, "/"));
    $netmask = substr(strstr($cidr_address, "/"), 1);

    $first_bin = str_pad(decbin(ip2long($first)), 32, "0", STR_PAD_LEFT);
    $netmask_bin = str_pad(str_repeat("1", (integer)$netmask), 32, "0", STR_PAD_RIGHT);

    for ($i = 0; $i < 32; $i++) {
        if ($netmask_bin[$i] == "1")
            $last_bin .= $first_bin[$i];
        else
            $last_bin .= "1";
    }

    $last = long2ip(bindec($last_bin));

    return array($first, $last);
}
?>

So you can enter 190.151.192/18 as $incomplete_cidr_notation and get

<?php
(
    [0] => 190.151.192.0
    [1] => 190.151.255.255
)
?>

But even if you enter 17/8 (or with a leading zero, straight out of IANAs IP allocation file) it will work and you'll get, in this case, Apple's IP range

<?php
(
    [0] => 17.0.0.0
    [1] => 17.255.255.255
)
?>

Update: Since this article is getting quite a few hits and when I read this back it seemed kinda confusing, I've recreated this a bit better as a Gist.