4

Suppose there are leading zeros in IPv4 address representation such as 012.012.012.012.

To suppress the leading zeros, I simply write the following code, and it works as I expected on my Mac:

% php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
Command line code:1:
string(11) "12.12.12.12"

% php --version
PHP 7.3.25 (cli) (built: Dec 25 2020 22:03:38) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.25, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans

But this simple piece of code doesn't work on CentOS 7, it seems like ip2long("012.012.012.012") returns false value:

$ php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
string(7) "0.0.0.0"

$ php --version
PHP 7.3.25 (cli) (built: Nov 24 2020 11:10:55) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies

$ cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)

Both PHP versions are identical and I would expect them to return exact same values. I also read the ip2long docs and tried to find if there is any special options/configurations for this behaviour, but no luck.

Could someone lead me in the right direction? What makes them different? And what should I do?

0stone0
  • 34,288
  • 4
  • 39
  • 64
ernix
  • 3,442
  • 1
  • 17
  • 23
  • 1
    [3v4l:](https://3v4l.org/jWdv3) **4.3 - 5.2.9**: `"10.10.10.10"` | **5.2.10 - 8.0.1**: `"0.0.0.0"` – 0stone0 Jan 14 '21 at 13:13
  • 0stone0: So... Older versions of PHP treat each numbers as octal because of leading zero, and newer versions regard it as invalid? My Mac is neither of them though... – ernix Jan 14 '21 at 13:26
  • I've no clue ;) My mac (7.4.9 - 10.15.7) says `12.12.12.12` where my Debian9 (7.2.24) says `0.0.0.0`. – 0stone0 Jan 14 '21 at 13:28
  • 1
    ip2long returns false when the ip address is invalid, and on a CentOS system I have access to, 012.012.012.012 returned false, while 12.12.12.12 returned 202116108. I'm looking around for more info, but it might be a Linux thing – Russ Jan 14 '21 at 13:30
  • Looks like the behavior has been around for at least 6 years. An entry here warns of this behavior: https://www.php.net/manual/en/function.inet-pton.php. Based on this, it sounds like you should pre-process the IP address to remove leading zeroes. – Russ Jan 14 '21 at 13:39
  • ip2long(“012.012.012.012”) returns always false, because is isn't a valid IpV4. A leading 0 is not allowed according to RFC ! – jspit Jan 14 '21 at 14:58
  • jspit: Could you provide me which RFC mentions? RFC790 contains `010.020.000.052` as an example. https://tools.ietf.org/html/rfc790 – ernix Jan 14 '21 at 15:31

1 Answers1

1

OK, I found the culprit. Different implementation of inet_pton(3) between LLVM and GCC leads this behaviour, as Russ-san commented. There was a bug report about the exact same problem 6 years ago. It seems PHP v5.2.10 had started using inet_pton instead of inet_addr according to this patch, that's why older versions of PHP treat each chunks as octal.

test.c

#include <stdio.h>
#include <arpa/inet.h>

#define INADDR "012.012.012.012"

int main() {
    struct in_addr inaddr;

    if (inet_pton(AF_INET, INADDR, &inaddr) == 0) {
        printf("Invalid: %s\n", INADDR);
    }
    else {
        printf("Valid: %s\n", INADDR);
    }

    return 0;
}
  • Mac
% cc test.cc && ./a.out
Valid: 012.012.012.012
  • Linux
$ cc test.cc && ./a.out
Invalid: 012.012.012.012

I gave up using ip2long / long2ip built-in functions and now trying to use https://github.com/mlocati/ip-lib

>>> \IPLib\Address\IPv4::fromString("1.2.3.12")->toString(true);
=> "001.002.003.012"
>>> \IPLib\Address\IPv4::fromString("001.002.003.012")->toString();
=> "1.2.3.12"

No problems so far.

ernix
  • 3,442
  • 1
  • 17
  • 23