diff options
author | Igor Wiedler <igor@wiedler.ch> | 2011-01-03 00:24:55 +0100 |
---|---|---|
committer | Igor Wiedler <igor@wiedler.ch> | 2011-01-03 00:24:55 +0100 |
commit | da4617b14b11ade6f664b8c1ab94e3aeb5b7428d (patch) | |
tree | e22342e6ff9ff74b6a1d3286b31985ca25fbc1e3 | |
parent | 979158f0a2e1ab88685f608e8756ff40248b86cf (diff) | |
parent | 3c713b5e7d883d7414538de0557c68195cd73018 (diff) | |
download | forums-da4617b14b11ade6f664b8c1ab94e3aeb5b7428d.tar forums-da4617b14b11ade6f664b8c1ab94e3aeb5b7428d.tar.gz forums-da4617b14b11ade6f664b8c1ab94e3aeb5b7428d.tar.bz2 forums-da4617b14b11ade6f664b8c1ab94e3aeb5b7428d.tar.xz forums-da4617b14b11ade6f664b8c1ab94e3aeb5b7428d.zip |
Merge branch 'ticket/bantu/9746' into develop
-rw-r--r-- | phpBB/includes/acp/acp_users.php | 2 | ||||
-rw-r--r-- | phpBB/includes/functions.php | 182 | ||||
-rw-r--r-- | phpBB/includes/session.php | 18 | ||||
-rw-r--r-- | phpBB/install/database_update.php | 7 | ||||
-rw-r--r-- | phpBB/install/install_install.php | 3 | ||||
-rw-r--r-- | tests/network/all_tests.php | 4 | ||||
-rw-r--r-- | tests/network/inet_ntop_pton.php | 55 | ||||
-rw-r--r-- | tests/network/ip_normalise.php | 65 |
8 files changed, 331 insertions, 5 deletions
diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 79c594ed6d..006c3617f7 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -56,7 +56,7 @@ class acp_users $this->page_title = 'WHOIS'; $this->tpl_name = 'simple_body'; - $user_ip = request_var('user_ip', ''); + $user_ip = phpbb_ip_normalise(request_var('user_ip', '')); $domain = gethostbyaddr($user_ip); $ipwhois = user_ipwhois($user_ip); diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 285c3938c1..41dad77141 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3281,6 +3281,188 @@ function short_ipv6($ip, $length) } /** +* Normalises an internet protocol address, +* also checks whether the specified address is valid. +* +* IPv4 addresses are returned 'as is'. +* +* IPv6 addresses are normalised according to +* A Recommendation for IPv6 Address Text Representation +* http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07 +* +* @param string $address IP address +* +* @return mixed false if specified address is not valid, +* string otherwise +* +* @author bantu +*/ +function phpbb_ip_normalise($address) +{ + $address = trim($address); + + if (empty($address) || !is_string($address)) + { + return false; + } + + if (preg_match(get_preg_expression('ipv4'), $address)) + { + return $address; + } + + return phpbb_inet_ntop(phpbb_inet_pton($address)); +} + +/** +* Wrapper for inet_ntop() +* +* Converts a packed internet address to a human readable representation +* inet_ntop() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. +* +* @param string $in_addr A 32bit IPv4, or 128bit IPv6 address. +* +* @return mixed false on failure, +* string otherwise +* +* @author APTX +*/ +function phpbb_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; + } +} + +/** +* Wrapper for inet_pton() +* +* Converts a human readable IP address to its packed in_addr representation +* inet_pton() is supported by PHP since 5.1.0, since 5.3.0 also on Windows. +* +* @param string $address A human readable IPv4 or IPv6 address. +* +* @return mixed false if address is invalid, +* in_addr representation of the given address otherwise (string) +* +* @author APTX +*/ +function phpbb_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; +} + +/** * Wrapper for php's checkdnsrr function. * * @param string $host Fully-Qualified Domain Name diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 0f1b1314c2..c4cc17d2a4 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -279,6 +279,24 @@ class session foreach ($ips as $ip) { + if (function_exists('phpbb_ip_normalise')) + { + // Normalise IP address + $ip = phpbb_ip_normalise($ip); + + if (empty($ip)) + { + // IP address is invalid. + break; + } + + // IP address is valid. + $this->ip = $ip; + + // Skip legacy code. + continue; + } + // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) { diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 9aa7a34f6b..b33c0f4a11 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -127,8 +127,11 @@ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false); // We do not need this any longer, unset for safety purposes unset($dbpasswd); -$user->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : ''; -$user->ip = (stripos($user->ip, '::ffff:') === 0) ? substr($user->ip, 7) : $user->ip; +$user->ip = ''; +if (!empty($_SERVER['REMOTE_ADDR'])) +{ + $user->ip = (function_exists('phpbb_ip_normalise')) ? phpbb_ip_normalise($_SERVER['REMOTE_ADDR']) : htmlspecialchars($_SERVER['REMOTE_ADDR']); +} $sql = "SELECT config_value FROM " . CONFIG_TABLE . " diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index eaad2ed7e0..8143ea7737 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -1235,8 +1235,7 @@ class install_install extends module $current_time = time(); - $user_ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : ''; - $user_ip = (stripos($user_ip, '::ffff:') === 0) ? substr($user_ip, 7) : $user_ip; + $user_ip = (!empty($_SERVER['REMOTE_ADDR'])) ? phpbb_ip_normalise($_SERVER['REMOTE_ADDR']) : ''; if ($data['script_path'] !== '/') { diff --git a/tests/network/all_tests.php b/tests/network/all_tests.php index b500647f81..fd36009f4c 100644 --- a/tests/network/all_tests.php +++ b/tests/network/all_tests.php @@ -16,6 +16,8 @@ require_once 'test_framework/framework.php'; require_once 'PHPUnit/TextUI/TestRunner.php'; require_once 'network/checkdnsrr.php'; +require_once 'network/inet_ntop_pton.php'; +require_once 'network/ip_normalise.php'; class phpbb_network_all_tests { @@ -29,6 +31,8 @@ class phpbb_network_all_tests $suite = new PHPUnit_Framework_TestSuite('phpBB Network Functions'); $suite->addTestSuite('phpbb_network_checkdnsrr_test'); + $suite->addTestSuite('phpbb_network_inet_ntop_pton_test'); + $suite->addTestSuite('phpbb_network_ip_normalise_test'); return $suite; } diff --git a/tests/network/inet_ntop_pton.php b/tests/network/inet_ntop_pton.php new file mode 100644 index 0000000000..4cea6cfa3a --- /dev/null +++ b/tests/network/inet_ntop_pton.php @@ -0,0 +1,55 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +require_once 'test_framework/framework.php'; +require_once '../phpBB/includes/functions.php'; + +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('13.1.68.3', '0d014403'), + array('129.144.52.38', '81903426'), + + 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'), + ); + } + + /** + * @dataProvider data_provider + */ + public function test_inet_ntop($address, $hex) + { + $this->assertEquals($address, phpbb_inet_ntop(pack('H*', $hex))); + } + + /** + * @dataProvider data_provider + */ + public function test_inet_pton($address, $hex) + { + $this->assertEquals($hex, bin2hex(phpbb_inet_pton($address))); + } +} diff --git a/tests/network/ip_normalise.php b/tests/network/ip_normalise.php new file mode 100644 index 0000000000..53d41e9371 --- /dev/null +++ b/tests/network/ip_normalise.php @@ -0,0 +1,65 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +require_once 'test_framework/framework.php'; +require_once '../phpBB/includes/functions.php'; + +class phpbb_network_ip_normalise_test extends phpbb_test_case +{ + public function data_provider() + { + return array( + // From: A Recommendation for IPv6 Address Text Representation + // http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07 + + // Section 4: A Recommendation for IPv6 Text Representation + // Section 4.1: Handling Leading Zeros in a 16 Bit Field + array('2001:0db8::0001', '2001:db8::1'), + + // Section 4.2: "::" Usage + // Section 4.2.1: Shorten As Much As Possible + array('2001:db8::0:1', '2001:db8::1'), + + // Section 4.2.2: Handling One 16 Bit 0 Field + array('2001:db8::1:1:1:1:1', '2001:db8:0:1:1:1:1:1'), + + // Section 4.2.3: Choice in Placement of "::" + array('2001:db8:0:0:1:0:0:1', '2001:db8::1:0:0:1'), + + // Section 4.3: Lower Case + array('2001:DB8::1', '2001:db8::1'), + + // Section 5: Text Representation of Special Addresses + // We want to show IPv4-mapped addresses as plain IPv4 addresses, though. + array('::ffff:192.168.0.1', '192.168.0.1'), + array('0000::0000:ffff:c000:0280', '192.0.2.128'), + + // IPv6 addresses with the last 32-bit written in dotted-quad notation + // should be converted to hex-only IPv6 addresses. + array('2001:db8::192.0.2.128', '2001:db8::c000:280'), + + // Any string not passing the IPv4 or IPv6 regular expression + // is supposed to result in false being returned. + // Valid and invalid IP addresses are tested in + // tests/regex/ipv4.php and tests/regex/ipv6.php. + array('', false), + array('192.168.1.256', false), + array('::ffff:192.168.255.256', false), + array('::1111:2222:3333:4444:5555:6666::', false), + ); + } + + /** + * @dataProvider data_provider + */ + public function test_ip_normalise($ip_address, $expected) + { + $this->assertEquals($expected, phpbb_ip_normalise($ip_address)); + } +} |