diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 0b747058f7..ac3641ae17 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3343,10 +3343,65 @@ function phpbb_ip_normalise($address) * * @return mixed false on failure, * string otherwise +* +* @author APTX */ function phpbb_inet_ntop($in_addr) { - return inet_ntop($in_addr); + $in_addr = bin2hex($in_addr); + + switch (strlen($in_addr)) + { + case 8: + return implode('.', array_map('hexdec', str_split($in_addr, 2))); + + case 32: + if (substr($in_addr, 0, 24) === '00000000000000000000ffff') + { + return phpbb_inet_ntop(pack('H*', substr($in_addr, 24))); + } + + $parts = str_split($in_addr, 4); + $parts = preg_replace('/^0+(?!$)/', '', $parts); + $ret = implode(':', $parts); + + $matches = array(); + preg_match_all('/(?<=:|^)(?::?0){2,}/', $ret, $matches, PREG_OFFSET_CAPTURE); + $matches = $matches[0]; + + if (empty($matches)) + { + return $ret; + } + + $longest_match = ''; + $longest_match_offset = 0; + foreach ($matches as $match) + { + if (strlen($match[0]) > strlen($longest_match)) + { + $longest_match = $match[0]; + $longest_match_offset = $match[1]; + } + } + + $ret = substr_replace($ret, '', $longest_match_offset, strlen($longest_match)); + + if ($longest_match_offset == strlen($ret)) + { + $ret .= ':'; + } + + if ($longest_match_offset == 0) + { + $ret = ':' . $ret; + } + + return $ret; + + default: + return false; + } } /** @@ -3358,10 +3413,71 @@ function phpbb_inet_ntop($in_addr) * @param string $address A human readable IPv4 or IPv6 address. * * @return string in_addr representation of the given address +* +* @author APTX */ function phpbb_inet_pton($address) { - return inet_pton($address); + $ret = ''; + if (preg_match(get_preg_expression('ipv4'), $address)) + { + foreach (explode('.', $address) as $part) + { + $ret .= ($part <= 0xF ? '0' : '') . dechex($part); + } + + return pack('H*', $ret); + } + + if (preg_match(get_preg_expression('ipv6'), $address)) + { + $parts = explode(':', $address); + $missing_parts = 8 - sizeof($parts) + 1; + + if (substr($address, 0, 2) === '::') + { + ++$missing_parts; + } + + if (substr($address, -2) === '::') + { + ++$missing_parts; + } + + $embedded_ipv4 = false; + $last_part = end($parts); + + if (preg_match(get_preg_expression('ipv4'), $last_part)) + { + $parts[sizeof($parts) - 1] = ''; + $last_part = phpbb_inet_pton($last_part); + $embedded_ipv4 = true; + --$missing_parts; + } + + foreach ($parts as $i => $part) + { + if (strlen($part)) + { + $ret .= str_pad($part, 4, '0', STR_PAD_LEFT); + } + else if ($i && $i < sizeof($parts) - 1) + { + $ret .= str_repeat('0000', $missing_parts); + } + } + + $ret = pack('H*', $ret); + + if ($embedded_ipv4) + { + $ret .= $last_part; + } + + return $ret; + } + + return false; } /** diff --git a/tests/network/inet_ntop_pton.php b/tests/network/inet_ntop_pton.php index 47fa0552da..4cea6cfa3a 100644 --- a/tests/network/inet_ntop_pton.php +++ b/tests/network/inet_ntop_pton.php @@ -15,12 +15,25 @@ class phpbb_network_inet_ntop_pton_test extends phpbb_test_case public function data_provider() { return array( - array('127.0.0.1', '7f000001'), - array('192.232.131.223', 'c0e883df'), + array('127.0.0.1', '7f000001'), + array('192.232.131.223', 'c0e883df'), + array('13.1.68.3', '0d014403'), + array('129.144.52.38', '81903426'), - array('::1', '00000000000000000000000000000001'), - array('2001:280:0:10::5', '20010280000000100000000000000005'), - array('fe80::200:4cff:fefe:172f', 'fe8000000000000002004cfffefe172f'), + array('2001:280:0:10::5', '20010280000000100000000000000005'), + array('fe80::200:4cff:fefe:172f', 'fe8000000000000002004cfffefe172f'), + + array('::', '00000000000000000000000000000000'), + array('::1', '00000000000000000000000000000001'), + array('1::', '00010000000000000000000000000000'), + + array('1:1:0:0:1::', '00010001000000000001000000000000'), + + array('0:2:3:4:5:6:7:8', '00000002000300040005000600070008'), + array('1:2:0:4:5:6:7:8', '00010002000000040005000600070008'), + array('1:2:3:4:5:6:7:0', '00010002000300040005000600070000'), + + array('2001:0:0:1::1', '20010000000000010000000000000001'), ); }