Netmasks and IP addresses in PHP

Zeppy asked the following:

I have an output of IP subnets wich is like: one subnet of /22, two subnets of /23, 4 subnets of /24. Anyone knows how to make a tree of these until /32? I want to make a tree, like an array. For example the /22 contains two of /23, each /23 contains two /24, etc.

Let's first look at what the netmask of an IP address indicates.

192.168.0.0/22
The netmask in this IP address indicates that all addresses in this netmask have the first 22 bits the same as 192.168.0.0. So that is the first 2 bytes and the first 6 bytes of the third number. The IPs in the subnet look like 192.168.x.y, where y can be anything and x can have only its lower two bits anything else than 0. Thus the addresses range from 192.168.0.0 to 192.168.3.255.

To solve the problem, we vary the leftmost bit which is not part of the mask. We set it to 0, we get the lowest address (192.168.0.0). We set it to 1, we get an address halfway our range (192.168.2.0). Thus, we have split our subnet in halve and created two subnets.

Below is the code. It recursively splits subnets in half by setting or clearing the bit.

> ($netmask - 1) ;
	$longip1 = $longip & (~$mask);
	$longip2 = $longip | $mask;
	$strip1 = long2ip($longip1);
	$strip2 = long2ip($longip2);
	return array($strip1 => makeTree($longip1, $netmask + 1),
				 $strip2 => makeTree($longip2, $netmask + 1));
}
?>

Line 11 creates a bitmask, containing of one 1 which is moved to the right depending on the bitmask. Actually this should be 0x80000000, but that seems to overflow PHP native data type for integers, so we just reduce the netmask with 1. The variables $longip1 and $longip2 contain the IP as a number with the bit cleared and set, respectively. These are converted to strings and added to the array. The output looks like this:

Array
(
    [192.168.0.0] => Array
        (
            [192.168.0.0] => Array
                (
                    [192.168.0.0] => 
                    [192.168.0.128] => 
                )
            [192.168.1.0] => Array
                (
                    [192.168.1.0] => 
                    [192.168.1.128] => 
                )
        )
    [192.168.2.0] => Array
        (
            [192.168.2.0] => Array
                (
                    [192.168.2.0] => 
                    [192.168.2.128] => 
                )

            [192.168.3.0] => Array
                (
                    [192.168.3.0] => 
                    [192.168.3.128] => 
                )
        )
)