0

My system includes a third party box that stores IP addresses and compares them to values sent from my Web interface. I have a problem that a user entered the netmask for the third party box as 255.255.255.000, and the box stored it as 255.255.255.0. However the next time the box reboots and is told that the mask includes 000 it concludes that these values are different and updates its database and reboots. And reboots. And reboots.

My intent is to solve this by storing the netmask in my own system in the simplified form 255.255.255.0 (and as another example store 010.001.002.005 as 10.1.2.5). But I'm brand new to PHP. I tried code $mask = long2ip(ip2long($mask)) to convert the entry to a standardized form but just got back 0.0.0.0. Is there something special I need to do to convert the IP to long and back? Is there a better way to simplify this?

Sinc
  • 553
  • 1
  • 8
  • 31
  • 1
    Why not use explode() by the dot and make an int cast for each element (which would remove the leading zero)? – ka_lin Feb 05 '19 at 15:50
  • @ka_lin As I said I'm brand new to PHP. Can you expand that into real code for processing the field and add it as a possible answer? Thanks – Sinc Feb 05 '19 at 15:52
  • Why not validate the user input before using it? – Nico Haase Feb 05 '19 at 16:09

3 Answers3

2

To follow the suggestion by @ka_lin in the comments, just explode it into parts, convert it to an int which will drop leading 0's and rebuild it with implode...

$mask = implode(".", array_map("intval", explode(".", $mask)));

A simple and less overhead version assumes 4 parts to the IP address...

list ($o1, $o2, $o3, $o4) = explode(".", $mask);
$mask = (int)$o1.".".(int)$o2.".".(int)$o3.".".(int)$o4;

It is difficult as 010.001.002.005 is a valid IP address, but could also be confusing (sometimes numbers starting with a 0 are octal).

Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
1

ip2long returns false on an error and it doesn't seem to detect 000 as valid. Since 255.255.255.000 isn't detected as a valid IP, it will return false, so long2ip(false) won't spit out a valid IP.

You could just check that ip2long(input) returns true before even accepting the IP address. Having proper validation in place would prevent invalid IPs from breaking the system. Trying to implement auto-correction for all of the possible invalid IP addresses is going to be much harder than just enforcing a valid IP to begin with.

Devon Bessemer
  • 34,461
  • 9
  • 69
  • 95
  • Interesting. I would expect the .000 to be valid just not simple. So you're saying that always using three decimal digits is invalid, the integer must be without leading zeroes? 010.001.002.005 is not a valid IP address? If that's true then I would definitely need to move the validation up higher in the logical path. – Sinc Feb 05 '19 at 15:59
  • @Sinc yeah I updated my answer since 000 is actually valid, but ip2long doesn't detect it as such. – Devon Bessemer Feb 05 '19 at 16:06
  • You should really check that `ip2long()` returns `!== false` as `0.0.0.0` => 0. Which is also why `long2ip(false)` => `0.0.0.0` – Nigel Ren Feb 05 '19 at 16:08
  • @Sinc, inet_pton doesn't work with leading zeroes either so none of the php ip libraries support a "000" address. – Devon Bessemer Feb 05 '19 at 16:09
  • @Devon, that seems narrow minded of the libraries. I thought that doing the double conversion would be the simplest way to get the simple IP address. I can picture some coders always printing the IP as %3d so it seems unfortunate that the library functions wouldn't support that. Thanks for checking. I'll have to move the validation upstream and probably force the user to correct the input. – Sinc Feb 05 '19 at 16:18
  • I don't think it's just PHP libraries, I think based on the inet_pton C library manpage, each part should be 0 to 255 stored in a struct in_addr, so I don't think `000` would be valid there either and PHP's implementation probably uses that library. – Devon Bessemer Feb 05 '19 at 16:23
1

A note: ip2long() has an issue: It doesn't accept the valid ip address 127.1 (classic a notation, but valid!) or 127.0.0.010 (RFC says invalid, but most read 010 as octal number).

The alternative if gethostbyname(). But gethostbyname() has issues too: If an invalid ip is entered (like 127.0.0.1234), it makes a DNS lookup and returns the source, if the lookup fails.

A solution can be:

long2ip(ip2long(gethostbyname($IP_ADDRESS)))

My personal solution is the following function:

function aton ( $addr )
{
    $l = explode('.',$addr);
    switch (count($l))
    {
        case 0: return FALSE;

        case 1: return intval($l[0]) & 0xffffffff;

        case 2: return  ( intval($l[0]) << 24
                        | intval($l[1])
                        ) & 0xffffffff;

        case 3: return  ( intval($l[0]) << 24
                        | intval($l[1]) << 16
                        | intval($l[2])
                        ) & 0xffffffff;

        default: return ( intval($l[0]) << 24
                        | intval($l[1]) << 16
                        | intval($l[2]) <<  8
                        | intval($l[3])
                        ) & 0xffffffff;
    }
}

With this function, you can use:

long2ip(aton($IP_ADDRESS))

btw, I had never issues with special ip addresses like 255.255.255.0.

Wiimm
  • 2,971
  • 1
  • 15
  • 25