Checking IP Ranges for Sanity / Validity

This doesn’t cover a lot of cases so it is really a sanity check for IP Ranges. It takes two IP addresses a low one and a high one and makes sure they are valid IPv4 addresses and it take a look to make sure (at least I hope it makes sure, anyone want to help me out here?) the low_ip is ‘lower’ than the high_ip.

This is used by some code that allows a user to specify an IP address range and then when the application ‘sees’ a client coming from within a known range, it associates the client with the ‘user’ who set up the range. (Think library systems that restrict content via institutional IPs)

$low_ip = '18.0.0.0';
$high_ip = '18.255.255.255';

if( validate_ip_range($low_ip, $high_ip) ) {
    print "yes\n";
} else {
    print "no\n";
}
function validate_ip_address($ip)
{
    if( ($long_ip = ip2long($ip)) !== false) {
        if($ip == long2ip($long_ip)) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

function validate_ip_range($low_ip, $high_ip)
{
    if(validate_ip_address($low_ip) && validate_ip_address($high_ip)) {
        $long_low_ip = ip2long($low_ip);
        $long_high_ip = ip2long($high_ip);
        if( ($low_ip == long2ip($long_low_ip)) && ($high_ip == long2ip($long_high_ip)) ) {
            if($long_low_ip <= $long_high_ip) {
                # now check that 1st octet matches in each ip (18.* == 18.*)
                $low_octets = explode(".", $low_ip);
                $high_octets = explode(".", $high_ip);
                if($low_octets[0] != $high_octets[0]) { return false; }
                # for each of the remaining 3 octets, low_ip's octet <= high ips.
                # e.g. 18.151.1.0 18.151.1.255
                # 18.57.0.41 - 18.57.0.100
                for($i = 1; $i < 4; $i++) {
                    if($low_octets[$i] > $high_octets[$i]) { return false; }
                }
                $num_ips = ( sprintf("%u", $long_high_ip) - sprintf("%u", $long_low_ip) );
                if($num_ips > 65535) { echo "warn: above a class C address space\n"; }
                # if we made it this far, should be a valid rang for our purposes
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}

Attached is a text file disguised as a .doc with the test “harness” for this function and the function suggested by tevis below. For malformed IP ranges such as $low_ip = ‘18.0.0.14’ and $high_ip = ‘18.255.255.1’; the suggestion below doesn’t seem to work, but the cumbersome process does correctly indicate that there’s a problem with that kind of IP range.

Advertisements

3 thoughts on “Checking IP Ranges for Sanity / Validity

  1. Unless I’m mistaken, you should be able to get away with something like the following, unless there is a specific reason that the first octets of each ip need to match.

    function validate_ip_range($low_ip, $high_ip)
    {
    if(validate_ip_address($low_ip) && validate_ip_address($high_ip)) {
    $long_low_ip = ip2long($low_ip);
    $long_high_ip = ip2long($high_ip);
    if($long_low_ip <= $long_high_ip) {
    if(($long_high_ip 65535) {
    echo “warn: above a class C address space\n”;
    }
    return true;
    } else {
    return false;
    }
    } else {
    return false;
    }
    }

    It seems to me that checking if each octet in the $low_octets is lower than is partner in the $high_octets would cause bad results with ranges like 18.0.2.0-18.1.1.1. I would think that converting to long and then checking which is greater would be all that is needed. Unless there is another reason for checking of course. I also see no reason to sprintf() the longs to subtract them, rather than just subtracting the longs, unless again I am missing something.

  2. @tevis I tried out your suggestion and, I think, came up with an example where it doesn’t work compared to the cumbersome process I’m currently using. Take a look at the test case, I would be great, for me, to simplify this code.

  3. @smbrown

    Apparently my code got a little mangled when It got posted as a comment. I’ve modified the code you posted to include the correct version of my function. This code only checks that the low_ip is lower than the high_ip, and both are valid ip’s. Assuming that is all you want to do, this code should work great.

    I looked at the test case you posted, and it would seem to me that $low_ip = ‘18.0.0.14′ and $high_ip = ‘18.255.255.1′; should be considered a valid range, providing that the only conditions are that low_ip is lower than high_ip, and they are both valid ips. Maybe I’m just missing one of the requirements, or I’m not very good with ip ranges :).

    You can see my code at http://trevisrouse.com/dev/iprange.txt to avoid any wordpress code mangling. Let me know if this makes sense, as I would like to know if I made any mistakes with regards to what is a valid ip range.

    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s