From dc7e3550ab6a4f95f12cbb366f3ad1a0568b8a2d Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Wed, 21 Jul 2010 18:59:02 +0200 Subject: [PATCH 1/9] [ticket/9746] Adding tests for phpbb_ip_normalise(). PHPBB3-9746 --- tests/network/all_tests.php | 2 ++ tests/network/ip_normalise.php | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/network/ip_normalise.php diff --git a/tests/network/all_tests.php b/tests/network/all_tests.php index b500647f81..6305aae5b8 100644 --- a/tests/network/all_tests.php +++ b/tests/network/all_tests.php @@ -16,6 +16,7 @@ require_once 'test_framework/framework.php'; require_once 'PHPUnit/TextUI/TestRunner.php'; require_once 'network/checkdnsrr.php'; +require_once 'network/ip_normalise.php'; class phpbb_network_all_tests { @@ -29,6 +30,7 @@ class phpbb_network_all_tests $suite = new PHPUnit_Framework_TestSuite('phpBB Network Functions'); $suite->addTestSuite('phpbb_network_checkdnsrr_test'); + $suite->addTestSuite('phpbb_network_ip_normalise_test'); return $suite; } 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 @@ +assertEquals($expected, phpbb_ip_normalise($ip_address)); + } +} From 8032549a15609b48d0a0daf08bd541582126a4c4 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 22 Jul 2010 00:18:46 +0200 Subject: [PATCH 2/9] [ticket/9746] Adding new function phpbb_ip_normalise(). This adds a function that normalises internet protocol addresses. While there should be no problem at all when handling IPv4 addresses, the many different representations of the exact same IPv6 address and webservers mapping IPv4-addresses into the IPv6 space made it necessary to add such a function. PHPBB3-9746 --- phpBB/includes/functions.php | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 285c3938c1..fad352f988 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3280,6 +3280,59 @@ function short_ipv6($ip, $length) return $ip; } +/** +* 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; + } + else if (preg_match(get_preg_expression('ipv6'), $address)) + { + $address = inet_ntop(inet_pton($address)); + + if (strpos($address, '::ffff:') === 0) + { + // IPv4-mapped address + $address_ipv4 = substr($address, 7); + + if (preg_match(get_preg_expression('ipv4'), $address_ipv4)) + { + return $address_ipv4; + } + + return false; + } + + return $address; + } + + return false; +} + /** * Wrapper for php's checkdnsrr function. * From 6a32724400e2647096d1bd124a4697d625652c02 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 22 Jul 2010 00:59:12 +0200 Subject: [PATCH 3/9] [ticket/9746] Adding calls to phpbb_ip_normalise() from session management. PHPBB3-9746 --- phpBB/includes/session.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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)) { From fdb5c2c9902557f0a3a006c7f62f2465c98513a7 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Thu, 22 Jul 2010 12:03:57 +0200 Subject: [PATCH 4/9] [ticket/9746] Adding unit tests for inet_ntop() and inet_pton(). PHPBB3-9746 --- tests/network/all_tests.php | 2 ++ tests/network/inet_ntop_pton.php | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/network/inet_ntop_pton.php diff --git a/tests/network/all_tests.php b/tests/network/all_tests.php index 6305aae5b8..fd36009f4c 100644 --- a/tests/network/all_tests.php +++ b/tests/network/all_tests.php @@ -16,6 +16,7 @@ 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 @@ -30,6 +31,7 @@ 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..47fa0552da --- /dev/null +++ b/tests/network/inet_ntop_pton.php @@ -0,0 +1,42 @@ +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))); + } +} From ae43221399d8d73b38d1f76da5b9ea6b7a6fbb5e Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 23 Jul 2010 10:35:55 +0200 Subject: [PATCH 5/9] [ticket/9746] Adding wrapper functions for inet_ntop() and inet_pton(). PHPBB3-9746 --- phpBB/includes/functions.php | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index fad352f988..0b747058f7 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3312,7 +3312,7 @@ function phpbb_ip_normalise($address) } else if (preg_match(get_preg_expression('ipv6'), $address)) { - $address = inet_ntop(inet_pton($address)); + $address = phpbb_inet_ntop(phpbb_inet_pton($address)); if (strpos($address, '::ffff:') === 0) { @@ -3333,6 +3333,37 @@ function phpbb_ip_normalise($address) return false; } +/** +* 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 +*/ +function phpbb_inet_ntop($in_addr) +{ + return inet_ntop($in_addr); +} + +/** +* 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 string in_addr representation of the given address +*/ +function phpbb_inet_pton($address) +{ + return inet_pton($address); +} + /** * Wrapper for php's checkdnsrr function. * From 2aa54bb1560303cc526f13d43b3df0d451acd9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20A=2E=20Ruszczy=C5=84ski?= Date: Thu, 29 Jul 2010 22:24:05 +0200 Subject: [PATCH 6/9] [ticket/9746] Added PHP implementation of inet_pton and inet_ntop. PHPBB3-9746 --- phpBB/includes/functions.php | 120 ++++++++++++++++++++++++++++++- tests/network/inet_ntop_pton.php | 23 ++++-- 2 files changed, 136 insertions(+), 7 deletions(-) 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'), ); } From 985151913c3a75d817db4746bc2dbf3a93e9b019 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 3 Aug 2010 11:07:40 +0200 Subject: [PATCH 7/9] [ticket/9746] Ease up phpbb_ip_normalise() function. PHPBB3-9746 --- phpBB/includes/functions.php | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ac3641ae17..3048825064 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3310,27 +3310,8 @@ function phpbb_ip_normalise($address) { return $address; } - else if (preg_match(get_preg_expression('ipv6'), $address)) - { - $address = phpbb_inet_ntop(phpbb_inet_pton($address)); - if (strpos($address, '::ffff:') === 0) - { - // IPv4-mapped address - $address_ipv4 = substr($address, 7); - - if (preg_match(get_preg_expression('ipv4'), $address_ipv4)) - { - return $address_ipv4; - } - - return false; - } - - return $address; - } - - return false; + return phpbb_inet_ntop(phpbb_inet_pton($address)); } /** From 5d01c58b7747b0a86431021757cf6aca298e88e7 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 3 Aug 2010 11:11:30 +0200 Subject: [PATCH 8/9] [ticket/9746] Update documentation of phpbb_inet_pton(). PHPBB3-9746 --- phpBB/includes/functions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 3048825064..41dad77141 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3393,7 +3393,8 @@ 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 +* @return mixed false if address is invalid, +* in_addr representation of the given address otherwise (string) * * @author APTX */ From 3c713b5e7d883d7414538de0557c68195cd73018 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Tue, 3 Aug 2010 11:41:01 +0200 Subject: [PATCH 9/9] [ticket/9746] Adding some more calls to phpbb_ip_normalise(). PHPBB3-9746 --- phpBB/includes/acp/acp_users.php | 2 +- phpBB/install/database_update.php | 7 +++++-- phpBB/install/install_install.php | 3 +-- 3 files changed, 7 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/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'] !== '/') {