Skip to content

When using 32-bit OS, automation errors can be seen due to subnet mask calculations #3310

Closed

Description

@panlinux

Describe the bug
Function automation_get_valid_mask() fails in in https://github.com/Cacti/cacti/blob/develop/lib/api_automation.php#L3029 when converting a binary string to integer on a 32bit architecture like armhf.

This results in errors like these in the logs:

02/27/2020 03:15:08 - ERROR PHP WARNING: long2ip() expects parameter 1 to be int, float given in file: /usr/share/cacti/site/lib/api_automation.php  on line: 3006
02/27/2020 03:15:08 - CMDPHP PHP ERROR WARNING Backtrace:  (/poller_automation.php[272]:automation_primeIPAddressTable(), /lib/api_automation.php[3179]:automation_calculate_total_ips(), /lib/api_automation.php[3128]:automation_get_network_info(), /lib/api_automation.php[3034]:automation_get_valid_mask(), /lib/api_automation.php[3006]:long2ip(), CactiErrorHandler())
02/27/2020 03:15:08 - ERROR PHP WARNING: long2ip() expects parameter 1 to be int, float given in file: /usr/share/cacti/site/lib/api_automation.php  on line: 3006
02/27/2020 03:15:08 - CMDPHP PHP ERROR WARNING Backtrace:  (/poller_automation.php[272]:automation_primeIPAddressTable(), /lib/api_automation.php[3182]:automation_calculate_start(), /lib/api_automation.php[3116]:automation_get_network_info(), /lib/api_automation.php[3034]:automation_get_valid_mask(), /lib/api_automation.php[3006]:long2ip(), CactiErrorHandler())

To Reproduce
The error is showing up in the DEP8 Ubuntu tests at http://autopkgtest.ubuntu.com/packages/cacti. One can see they are failing for armhf: http://autopkgtest.ubuntu.com/packages/cacti/focal/armhf

A simple way to reproduce it is to call the automation_get_valid_mask() function with any argument between 0 and 33. For example, 24, on an amd64 machine returns this (with some debugging of mine):

$ php ./automation_get_valid_mask.php 24

bindec(11111111111111111111111100000000):
4294967040
Array
(
    [cidr] => 24
    [subnet] => 255.255.255.0
    [count] => 255
)

On armhf, however:

$ php ./automation_get_valid_mask.php 24

bindec(11111111111111111111111100000000):
4294967040PHP Warning:  long2ip() expects parameter 1 to be int, float given in /home/ubuntu/automation_get_valid_mask.php on line 13

Array
(
    [cidr] => 24
    [subnet] => 
    [count] => 255
)

There are warnings about issues with 32bit architectures on https://www.php.net/manual/en/function.bindec.php and https://www.php.net/manual/en/function.long2ip.php

Expected behavior
On armhf 32bit, automation_get_valid_mask() should work properly. For example, return "255.255.255.0" for "subnet" when called with a range == 24.

Cacti server

  • OS: Ubuntu 20.04 Focal Fossa (development release)
  • php 7.3.15
  • architecture: armhf (32bits)

Misc
This is the script I used. I copied the function from lib/api_automation.php and added some debugging:

<?php
function automation_get_valid_mask($range) {
    $cidr = false;
    if (is_numeric($range)) {
        if ($range > 0 && $range < 33) {
            $cidr = $range;
	    $ones = str_repeat('1',$range);
	    $zeroes = str_repeat('0',32-$range);
	    echo "\nbindec(" . $ones . $zeroes . "):\n";
	    print_r(bindec($ones . $zeroes));
            $mask = array(
                'cidr' => $cidr,
                'subnet' => long2ip(bindec($ones . $zeroes)));
        } else {
            $mask = false;
        }
    } else {
        $mask = automation_get_valid_subnet_cidr($range);
    }

    if ($mask !== false) {
        $mask['count'] = bindec(str_repeat('0',$mask['cidr']) . str_repeat('1',32-$mask['cidr']));
        if ($mask['count'] == 0) {
            $mask['count'] = 1;
        }
    }
    return $mask;
}

$bits = strval($argv[1]);
$mask = automation_get_valid_mask($bits);
echo "\n";
print_r($mask);
?>

Activity

  1. changed the title [-]32bit failure: long2ip(bindec())[/-] [+]32bit failure in automation_get_valid_mask(): long2ip(bindec())[/+] on Mar 2, 2020
  2. TheWitness commented on Mar 2, 2020

    @TheWitness
    Member

    Can you do a pull request against the 1.2.x branch?

  3. panlinux commented on Mar 2, 2020

    @panlinux
    ContributorAuthor

    I wonder if this is enough to fix it? I'm wary of casting variable types and its behavior between different architectures:

    diff --git a/lib/api_automation.php b/lib/api_automation.php
    index a1373af08..c71b08705 100644
    --- a/lib/api_automation.php
    +++ b/lib/api_automation.php
    @@ -3003,7 +3003,7 @@ function automation_get_valid_mask($range) {
     			$cidr = $range;
     			$mask = array(
     				'cidr' => $cidr,
    -				'subnet' => long2ip(bindec(str_repeat('1',$range) . str_repeat('0',32-$range))));
    +				'subnet' => long2ip((int)bindec(str_repeat('1',$range) . str_repeat('0',32-$range))));
     		} else {
     			$mask = false;
     		}
  4. panlinux commented on Mar 2, 2020

    @panlinux
    ContributorAuthor

    With the casting change you mean?

  5. panlinux commented on Mar 2, 2020

    @panlinux
    ContributorAuthor

    Maybe this is better:

    diff --git a/lib/api_automation.php b/lib/api_automation.php
    index a1373af08..b9fffbeeb 100644
    --- a/lib/api_automation.php
    +++ b/lib/api_automation.php
    @@ -3003,7 +3003,7 @@ function automation_get_valid_mask($range) {
     			$cidr = $range;
     			$mask = array(
     				'cidr' => $cidr,
    -				'subnet' => long2ip(bindec(str_repeat('1',$range) . str_repeat('0',32-$range))));
    +				'subnet' => long2ip((2**$range-1) << (32-$range)))
     		} else {
     			$mask = false;
     		}
  6. added
    apiAPI related issues
    bugUndesired behaviour
    on Mar 2, 2020
  7. self-assigned this
    on Mar 2, 2020
  8. linked a pull request that will close this issueFix netmask on 32bit arches #3311on Mar 3, 2020
  9. netniV commented on Mar 5, 2020

    @netniV
    Member

    Has this been tested against PHP 5.4 or 5.5? I suspect not as I just noticed that Travis has moaned about the use of 2**

  10. panlinux commented on Mar 5, 2020

    @panlinux
    ContributorAuthor

    No, I didn't test against those versions of php. Is there no ** operator there, or is it an issue with parenthesis?

  11. netniV commented on Mar 5, 2020

    @netniV
    Member

    I was not sure, I briefly saw that Travis didn't like it, so I looked at the php docs:

    $a ** $b | Exponentiation | Result of raising $a to the $b'th power. Introduced in PHP 5.6.

    So, we can only use that if PHP 5.4 or later, which unfortunately mean we either roll back the change or make an if statement and accept that under 5.4/5.5, there is a flaw in the logic on little endian systems making it a known issue.

  12. panlinux commented on Mar 5, 2020

    @panlinux
    ContributorAuthor
  13. netniV commented on Mar 6, 2020

    @netniV
    Member

    That would be good thanks as unfortunately I don't have a system to test that against. Took me a while to come up with my original code but yours was a lot simpler :)

    Could we reverse the bit order depending on the endian using my original code for older PHP versions?

  14. panlinux commented on Mar 6, 2020

    @panlinux
    ContributorAuthor

    How far back in terms of PHP do you need to go?

  15. panlinux commented on Mar 6, 2020

    @panlinux
    ContributorAuthor

    If you prefer to leave your old code with "1" and "0" strings, then maybe the (int) casting change from #3310 (comment) would be best, but we would have to test on the old php versions as well.

    I did test the ** fix for endianess, and no changes were required, I'm guessing long2ip() knows about these things. At least in php7.3.

    The oldest php I can get is the one from Ubuntu Precise: 5.3.10.

  16. panlinux commented on Mar 6, 2020

    @panlinux
    ContributorAuthor

    This worked on precise's php 5.3.10:

    'subnet' => long2ip((pow(2,$range)-1) << (32-$range)));

    Let me try on other architectures now.

  17. panlinux commented on Mar 6, 2020

    @panlinux
    ContributorAuthor

    The oldest php I can get on big-endian (s390x in this case) is php 7.0.33, from ubuntu xenial, same from debian stretch. The script keeps working fine there, with the pow() modification. Would you like a PR for this change?

  18. netniV commented on Mar 6, 2020

    @netniV
    Member

    Sure if you already have it that would be great :) Otherwise I can just apply the change over the weekend.

  19. cigamit commented on Mar 8, 2020

    @cigamit
    Member

    The pow() function is working well in x86_64 on PHP5.4. So, I guess this is resolved then?

  20. added this to the 1.2.11 milestone on Mar 8, 2020
  21. netniV commented on Mar 8, 2020

    @netniV
    Member

    Yes, I believe so. Be nice when PHP 5 is no longer a worry.

  22. changed the title [-]32bit failure in automation_get_valid_mask(): long2ip(bindec())[/-] [+]When using 32-bit OS, automation errors can be seen due to subnet mask calculations[/+] on Apr 5, 2020
  23. locked and limited conversation to collaborators on Jul 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

apiAPI related issuesbugUndesired behaviourresolvedA fixed issue

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions