I\'ve seen various questions and answers around this site and I\'m still having difficulty wrapping my head around this problem (could be because I\'ve got a cold). Regardle
I created this php function in order to get the subnet splits of a network/range. It works with ipv4 or ipv6.
If php<5.4 then use this hex2bin function https://github.com/dompdf/dompdf/issues/1692
function divide_ip_range($cidr="2001:db8:abc:12ff::/54",$mindivs=2){ // input range 192.168.4.0/24 and returns array with the 1st range and 2nd range [0] => 192.168.4.0/25 , [1] => 192.168.4.127/25
$outarr=array();
list($ipaddr,$range) = explode('/', $cidr);
for($rngsplit=1;pow(2,$rngsplit)<$mindivs;$rngsplit++){} // find to how many networks to divide
$divs=pow(2,$rngsplit);
$divcidr=(int)$range+$rngsplit;
if(preg_match("/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/",$ipaddr)){ // IPv4
$ip_address_long = ip2long($ipaddr);
$ip_nmask_long=(-1 << (32 - $range));
$ip_net = $ip_address_long & $ip_nmask_long;
$ip_broadcast_invert = ~$ip_nmask_long;
$ip_last = ($ip_address_long | $ip_broadcast_invert) - 1;
$ip_broadcast = $ip_address_long | $ip_broadcast_invert;
$numofhosts=pow(2,32-$range)-2;
for ($i=0;$i<$divs;$i++){
$outarr[]=long2ip($ip_net+$i*ceil($numofhosts/$divs)+($i*ceil($numofhosts/$divs)%2) )."/$divcidr";
}
//echo "Net:$ipaddr/$range\nFirst:".long2ip($ip_net)."\nLast: ".long2ip($ip_last)."\nNumOfHosts:$numofhosts \n";
} else if (preg_match("/^[0-9a-f:]+$/",$ipaddr)) { // IPv6 section
$ip_addr_bin = inet_pton($ipaddr);
$ip_addr_hex = bin2hex($ip_addr_bin);
$flexbits = 128 - $range; // Calculate the number of 'flexible' bits for first net
$pos = 31; $addr_hex_first = $ip_addr_hex; $addr_hex_last = $ip_addr_hex;
while ($flexbits > 0) {
$orig_val = hexdec(substr($ip_addr_hex, $pos, 1)); // dec value of pos char. ex. f=15
$mask = 0xf << (min(4,$flexbits)); // calculate the subnet mask. min() prevents comparison to be negative
$new_val_first = $orig_val & $mask;
$addr_hex_first = substr_replace($addr_hex_first, dechex($new_val_first) , $pos, 1); // Put hex character in pos
$segmask=(pow(2,min(4,$flexbits))-1); // Last address: OR it with (2^flexbits)-1, with flexbits limited to 4 at a time
$new_val_last = $orig_val | $segmask;
$addr_hex_last = substr_replace($addr_hex_last, dechex($new_val_last) , $pos, 1);
$pos--; $flexbits -= 4; // Next nibble
}
$partpos=(4*floor($pos/4)); // The 4 digits that vary by the subnetting
$partfirst=substr($addr_hex_first,$partpos,4);
$partlast=substr($addr_hex_last,$partpos,4);
$numofhosts=(hexdec($partlast)+1-hexdec($partfirst));
for ($i=0;$i<$divs;$i++){
$partdiv=dechex(hexdec($partfirst)+$i*$numofhosts/$divs);
$addr_hex_div=substr_replace($addr_hex_first, $partdiv , $partpos, 4);
$outarr[]=inet_ntop(hex2bin($addr_hex_div))."/$divcidr";
}
//echo "Net:$ipaddr/$range\nFirst:".inet_ntop(hex2bin($addr_hex_first))."\nLast:".inet_ntop(hex2bin($addr_hex_last))."\nNumOfHosts:$numofhosts\nDivide at partpos:$partpos ($partlast+1-$partfirst)/$divs=$partdiv\n";
}
return $outarr;
}