How do you check if an IP range is private or not in PHP?

Most of the questions I've seen regarding validating private IP addresses in PHP have to do with checking if a particular IP address is private or not, or if an IP address exists in a specific range.

However, I want to be able to tell in PHP whether an IP range given in a format like "XXXX - YYYY" is an exclusively private range. It's just so clear I want to see if the range of integers is private or not. Examples:

10.0.0.1 - 10.0.0.14

will return true because all IP addresses in this range are internal.

10.0.0.1 - 127.0.0.16

will return false because not all IP addresses in this range are internal / private, even if the start and end points are.

My initial thought was to just check the start and end IPs and if they are internal then all is well. But as I said above, if I had a range, for example $range = '10.0.0.1 - 127.0.0.16'

, whereas the start and end IPs are considered private IPs, it covers IPs that are not internal, hence it is not exclusively an internal IP range.

I could generate every single IP within the range and check each one, but that seems incredibly inefficient.

Is there an easier and more efficient way to do this?

Edit: Just to make it more explicit for those marked as a duplicate: I'm not trying to check one given IP address and see if it's private. I want to check that every possible IP address in a given format range $range = '10.0.0.1 - 127.0.0.16'

is private. Doing something like this is way too slow and inefficient (assuming I blew up the line to get the start and end IPs):

<?php
function checkRange($start, $end)
{
    $start = ip2long($start);
    $end = ip2long($end);

    for ($i = $start; $i <= $end; $i++) {
        $ip = long2ip($i);
        if (!filter_var(
            $ip,
            FILTER_VALIDATE_IP,
            FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_IPV4
        )) {
            continue;
        }
        return false;
    }
    return true;
}

      

+3


source to share


2 answers


All private ranges in the IP space are separated by public ranges ( p

for private, _

for public):

__ppp___pppp___ppp___

      

If you want a user-defined range to be completely private, it must be fully enclosed in one of the private ranges ( u

for custom ranges all-private range = hits, x

for invalid ranges, is not done):



__ppp___pppp___ppp___
   uu
  u
    xxxxxxx
          uu
               u

      

Thus, we need to check if both input values ​​( $start

and $end

) are not only private, but in the same private range.

function checkRange($start, $end)
{
    $start = ip2long($start);
    $end   = ip2long($end);

    if (!$start || !$end)
        throw new Exception('Invalid input.');

    if ($start > $end)
        throw new Exception('Invalid range.'); // Alternative: switch $start and $end

    $range1_start = ip2long('10.0.0.0');
    $range1_end   = ip2long('10.255.255.255');
    $range2_start = ip2long('172.16.0.0');
    $range2_end   = ip2long('172.31.255.255');
    $range3_start = ip2long('192.168.0.0');
    $range3_end   = ip2long('192.168.255.255');

    return ($start >= $range1_start && $start <= $range1_end &&
            $end   >= $range1_start && $end   <= $range1_end) ||
           ($start >= $range2_start && $start <= $range2_end &&
            $end   >= $range2_start && $end   <= $range2_end) ||
           ($start >= $range3_start && $start <= $range3_end &&
            $end   >= $range3_start && $end   <= $range3_end);

}

      

+3


source


The IP address is a 32-bit number. It can be represented as four decimal places separated by a period, with each decimal place being 8 bits from a 32-bit number in base 10. PHP's built-in ip2long converts from IPv4 string notation to a standard 32-bit integer.

With that in mind (IPv4 string notation strings are only 32 bits long) you can easily find an algorithm that checks if an integer is in a certain range or if a range is inside another.



<?php

function check($start, $end) {
    $r10Start = ip2long('10.0.0.0');
    $r10End = ip2long('10.255.255.255');

    $r127Start = ip2long('127.0.0.0');
    $r127End = ip2long('127.255.255.255');

    if (
        ($start >= $r10Start && $end <= $r10End)
        || ($start >= $r127Start && $end <= $r127End)
    ) {
        return true;
    }

    return false;
}

var_dump(check(ip2long('10.0.0.1'), ip2long('10.0.0.14')));
var_dump(check(ip2long('10.0.0.1'), ip2long('127.0.0.16')));

      

0


source







All Articles