Ticket #41083: 41083.6.diff
File 41083.6.diff, 5.4 KB (added by , 7 years ago) |
---|
-
src/wp-admin/includes/class-wp-community-events.php
diff --git src/wp-admin/includes/class-wp-community-events.php src/wp-admin/includes/class-wp-community-events.php index a204f9cafe..79c4a85adb 100644
class WP_Community_Events { 233 233 * or false on failure. 234 234 */ 235 235 public static function get_unsafe_client_ip() { 236 $client_ip = false; 236 $client_ip = $netmask = false; 237 $ip_prefix = ''; 237 238 238 239 // In order of preference, with the best ones for this purpose first. 239 240 $address_headers = array( … … class WP_Community_Events { 260 261 } 261 262 } 262 263 263 // These functions are not available on Windows until PHP 5.3. 264 if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) { 265 if ( 4 === strlen( inet_pton( $client_ip ) ) ) { 266 $netmask = '255.255.255.0'; // ipv4. 267 } else { 268 $netmask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; // ipv6. 264 if ( ! $client_ip ) { 265 return false; 266 } 267 268 // Detect what kind of IP address this is. 269 $is_ipv6 = substr_count( $client_ip, ':' ) > 1; 270 $is_ipv4 = ( 3 === substr_count( $client_ip, '.' ) ); 271 272 if ( $is_ipv6 && $is_ipv4 ) { 273 // IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4. 274 $ip_prefix = '::ffff:'; 275 $client_ip = preg_replace( '/^\[?[0-9a-f:]*:/i', '', $client_ip ); 276 $client_ip = str_replace( ']', '', $client_ip ); 277 $is_ipv6 = false; 278 } 279 280 if ( $is_ipv6 ) { 281 // IPv6 addresses will always be enclosed in [] if there's a port. 282 $ip_start = 1; 283 $ip_end = (int) strpos( $client_ip, ']' ) - 1; 284 $netmask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; 285 286 // Strip the port (and [] from IPv6 addresses), if they exist. 287 if ( $ip_end > 0 ) { 288 $client_ip = substr( $client_ip, $ip_start, $ip_end ); 269 289 } 270 290 271 $client_ip = inet_ntop( inet_pton( $client_ip ) & inet_pton( $netmask ) ); 291 // Partially anonymize the IP by reducing it to the corresponding network ID. 292 if ( function_exists( 'inet_pton' ) && function_exists( 'inet_ntop' ) ) { 293 $client_ip = inet_ntop( inet_pton( $client_ip ) & inet_pton( $netmask ) ); 294 } 295 } elseif ( $is_ipv4 ) { 296 // Strip any port and partially anonymize the IP. 297 $last_octet_position = strrpos( $client_ip, '.' ); 298 $client_ip = substr( $client_ip, 0, $last_octet_position ) . '.0'; 299 } else { 300 return false; 272 301 } 273 302 274 return $client_ip; 303 // Restore the IPv6 prefix to compatibility mode addresses. 304 return $ip_prefix . $client_ip; 275 305 } 276 306 277 307 /** -
tests/phpunit/tests/admin/includesCommunityEvents.php
diff --git tests/phpunit/tests/admin/includesCommunityEvents.php tests/phpunit/tests/admin/includesCommunityEvents.php index ed5cc2caee..50b5623a28 100644
class Test_WP_Community_Events extends WP_UnitTestCase { 255 255 'filename' => '', 256 256 ); 257 257 } 258 259 /** 260 * Test that get_unsafe_client_ip() properly anonymizes all possible address formats 261 * 262 * @dataProvider data_get_unsafe_client_ip_anonymization 263 * 264 * @ticket 41083 265 */ 266 public function test_get_unsafe_client_ip_anonymization( $raw_ip, $expected_result ) { 267 $_SERVER['REMOTE_ADDR'] = $raw_ip; 268 $actual_result = WP_Community_Events::get_unsafe_client_ip(); 269 270 $this->assertEquals( $expected_result, $actual_result ); 271 } 272 273 public function data_get_unsafe_client_ip_anonymization() { 274 return array( 275 // Invalid IP. 276 array( 277 '', // Raw IP address 278 false, // Expected result 279 ), 280 // Invalid IP. Sometimes proxies add things like this, or other arbitrary strings. 281 array( 282 'unknown', 283 false, 284 ), 285 // IPv4, no port 286 array( 287 '10.20.30.45', 288 '10.20.30.0', 289 ), 290 // IPv4, port 291 array( 292 '10.20.30.45:20000', 293 '10.20.30.0', 294 ), 295 // IPv6, no port 296 array( 297 '2a03:2880:2110:df07:face:b00c::1', 298 '2a03:2880:2110:df07::', 299 ), 300 // IPv6, port 301 array( 302 '[2a03:2880:2110:df07:face:b00c::1]:20000', 303 '2a03:2880:2110:df07::', 304 ), 305 // IPv6, no port, reducible representation 306 array( 307 '0000:0000:0000:0000:0000:0000:0000:0001', 308 '::', 309 ), 310 // IPv6, no port, partially reducible representation 311 array( 312 '1000:0000:0000:0000:0000:0000:0000:0001', 313 '1000::', 314 ), 315 // IPv6, port, reducible representation 316 array( 317 '[0000:0000:0000:0000:0000:0000:0000:0001]:1234', 318 '::', 319 ), 320 // IPv6, port, partially reducible representation 321 array( 322 '[1000:0000:0000:0000:0000:0000:0000:0001]:5678', 323 '1000::', 324 ), 325 // IPv6, no port, reduced representation 326 array( 327 '::', 328 '::', 329 ), 330 // IPv6, no port, reduced representation 331 array( 332 '::1', 333 '::', 334 ), 335 // IPv6, port, reduced representation 336 array( 337 '[::]:20000', 338 '::', 339 ), 340 // IPv6, address brackets without port delimiter and number, reduced representation 341 array( 342 '[::1]', 343 '::', 344 ), 345 // IPv6, no port, compatibility mode 346 array( 347 '::ffff:10.15.20.25', 348 '::ffff:10.15.20.0', 349 ), 350 // IPv6, port, compatibility mode 351 array( 352 '[::ffff:10.15.20.25]:30000', 353 '::ffff:10.15.20.0', 354 ), 355 // IPv6, no port, compatibility mode shorthand 356 array( 357 '::127.0.0.1', 358 '::ffff:127.0.0.0', 359 ), 360 // IPv6, port, compatibility mode shorthand 361 array( 362 '[::127.0.0.1]:30000', 363 '::ffff:127.0.0.0', 364 ), 365 ); 366 } 258 367 }