ip2long("012.012.012.012") returns false on Linux

Viewed 136

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?

1 Answers

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.

Related