http://modulesgarden.com * CONTACT -> contact@modulesgarden.com * * * This software is furnished under a license and may be used and copied * only in accordance with the terms of such license and with the * inclusion of the above copyright notice. This software or any other * copies thereof may not be provided or otherwise made available to any * other person. No title to and ownership of the software is hereby * transferred. * * * ******************************************************************** */ namespace ModulesGarden\ProxmoxAddon\App\Libs; if (!function_exists('ipv6_range')) { function ipv6_range($prefix) { // Split in address and prefix length list($firstaddrstr, $prefixlen) = explode('/', $prefix); // Parse the address into a binary string $firstaddrbin = inet_pton($firstaddrstr); // Convert the binary string to a string with hexadecimal characters # unpack() can be replaced with bin2hex() # unpack() is used for symmetry with pack() below $unpacked = unpack('H*', $firstaddrbin); $firstaddrhex = reset($unpacked); // Overwriting first address string to make sure notation is optimal $firstaddrstr = inet_ntop($firstaddrbin); // Calculate the number of 'flexible' bits $flexbits = 128 - $prefixlen; // Build the hexadecimal string of the last address $lastaddrhex = $firstaddrhex; // We start at the end of the string (which is always 32 characters long) $pos = 31; while ($flexbits > 0) { // Get the character at this position $orig = substr($lastaddrhex, $pos, 1); // Convert it to an integer $origval = hexdec($orig); // OR it with (2^flexbits)-1, with flexbits limited to 4 at a time $newval = $origval | (pow(2, min(4, $flexbits)) - 1); // Convert it back to a hexadecimal character $new = dechex($newval); // And put that character back in the string $lastaddrhex = substr_replace($lastaddrhex, $new, $pos, 1); // We processed one nibble, move to previous position $flexbits -= 4; $pos -= 1; } // Convert the hexadecimal string to a binary string # Using pack() here # Newer PHP version can use hex2bin() $lastaddrbin = pack('H*', $lastaddrhex); // And create an IPv6 address from the binary string $lastaddrstr = inet_ntop($lastaddrbin); return [$prefix, $firstaddrstr, $lastaddrstr]; } } /** * Converts human readable representation to a 128bit int * which can be stored in MySQL using DECIMAL(39,0). * * Requires PHP to be compiled with IPv6 support. * This could be made to work without IPv6 support but * I don't think there would be much use for it if PHP * doesn't support IPv6. * * @param string $ip IPv4 or IPv6 address to convert * @return string 128bit string that can be used with DECIMNAL(39,0) or false */ if (!function_exists('inet_ptoi')) { function inet_ptoi($ip) { // make sure it is an ip if (filter_var($ip, FILTER_VALIDATE_IP) === false) { return false; } $parts = unpack('N*', inet_pton($ip)); // fix IPv4 if (strpos($ip, '.') !== false) { $parts = [1 => 0, 2 => 0, 3 => 0, 4 => $parts[1]]; } foreach ($parts as &$part) { // convert any unsigned ints to signed from unpack. // this should be OK as it will be a PHP float not an int if ($part < 0) { $part += 4294967296; } } // use BCMath if the extension exists if (function_exists('bcadd')) { $decimal = $parts[4]; $decimal = bcadd($decimal, bcmul($parts[3], '4294967296')); $decimal = bcadd($decimal, bcmul($parts[2], '18446744073709551616')); $decimal = bcadd($decimal, bcmul($parts[1], '79228162514264337593543950336')); } // otherwise use the pure PHP BigInteger else { $decimal = new BigInteger($parts[4]); $part3 = new BigInteger($parts[3]); $part2 = new BigInteger($parts[2]); $part1 = new BigInteger($parts[1]); $decimal = $decimal->add($part3->multiply(new BigInteger('4294967296'))); $decimal = $decimal->add($part2->multiply(new BigInteger('18446744073709551616'))); $decimal = $decimal->add($part1->multiply(new BigInteger('79228162514264337593543950336'))); $decimal = $decimal->toString(); } return $decimal; } } /** * Converts a 128bit int to a human readable representation. * * Requires PHP to be compiled with IPv6 support. * This could be made to work without IPv6 support but * I don't think there would be much use for it if PHP * doesn't support IPv6. * * @param string $decimal 128bit int * @return string IPv4 or IPv6 */ if (!function_exists('inet_itop')) { function inet_itop($decimal) { $parts = []; // use BCMath if the extension exists if (function_exists('bcadd')) { $parts[1] = bcdiv($decimal, '79228162514264337593543950336', 0); $decimal = bcsub($decimal, bcmul($parts[1], '79228162514264337593543950336')); $parts[2] = bcdiv($decimal, '18446744073709551616', 0); $decimal = bcsub($decimal, bcmul($parts[2], '18446744073709551616')); $parts[3] = bcdiv($decimal, '4294967296', 0); $decimal = bcsub($decimal, bcmul($parts[3], '4294967296')); $parts[4] = $decimal; } // otherwise use the pure PHP BigInteger else { $decimal = new BigInteger($decimal); list($parts[1],) = $decimal->divide(new BigInteger('79228162514264337593543950336')); $decimal = $decimal->subtract($parts[1]->multiply(new BigInteger('79228162514264337593543950336'))); list($parts[2],) = $decimal->divide(new BigInteger('18446744073709551616')); $decimal = $decimal->subtract($parts[2]->multiply(new BigInteger('18446744073709551616'))); list($parts[3],) = $decimal->divide(new BigInteger('4294967296')); $decimal = $decimal->subtract($parts[3]->multiply(new BigInteger('4294967296'))); $parts[4] = $decimal; $parts[1] = $parts[1]->toString(); $parts[2] = $parts[2]->toString(); $parts[3] = $parts[3]->toString(); $parts[4] = $parts[4]->toString(); } foreach ($parts as &$part) { // convert any signed ints to unsigned for pack // this should be fine as it will be treated as a float if ($part > 2147483647) { $part -= 4294967296; } } $ip = inet_ntop(pack('N4', $parts[1], $parts[2], $parts[3], $parts[4])); // fix IPv4 by removing :: from the beginning if (strpos($ip, '.') !== false) { return substr($ip, 2); } return $ip; } }