From f65ce02ff98d269e8afbba1bf4c10f1b686cb045 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Sun, 13 Feb 2011 23:24:48 +0000 Subject: [PATCH] * (bug 27353) IPv6 address ending in "::WORD" was not recognized * Moved down 'contains no "::"' alternative for clarity (and possibly use frequency too) * Added more IPv6 tests --- includes/IP.php | 15 ++++++++------- tests/phpunit/includes/IPTest.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/includes/IP.php b/includes/IP.php index 0883992636..e64c0ca5e2 100644 --- a/includes/IP.php +++ b/includes/IP.php @@ -39,17 +39,18 @@ define( 'RE_IPV6_ADD', ':(?::|(?::' . RE_IPV6_WORD . '){1,7})' . '|' . // ends with "::" (except "::") RE_IPV6_WORD . '(?::' . RE_IPV6_WORD . '){0,6}::' . - '|' . // contains no "::" - RE_IPV6_WORD . '(?::' . RE_IPV6_WORD . '){7}' . - '|' . // contains one "::" in the middle and 2 words - RE_IPV6_WORD . '::' . RE_IPV6_WORD . - '|' . // contains one "::" in the middle and 3+ words (awkward regex for PCRE 4.0+) + '|' . // contains one "::" in the middle, ending in "::WORD" + RE_IPV6_WORD . '(?::' . RE_IPV6_WORD . '){0,5}' . '::' . RE_IPV6_WORD . + '|' . // contains one "::" in the middle, not ending in "::WORD" (regex for PCRE 4.0+) RE_IPV6_WORD . '(?::(?P:(?P))?' . RE_IPV6_WORD . '(?!:(?P=abn))){1,5}' . ':' . RE_IPV6_WORD . '(?P=iabn)' . // NOTE: (?!(?P=abn)) fails iff "::" used twice; (?P=iabn) passes iff a "::" was found. - // RegExp (PCRE 7.2+ only) for last 2 cases that allows easy regex concatenation: - #RE_IPV6_WORD . '(?::((?(-1)|:))?' . RE_IPV6_WORD . '){1,6}(?(-2)|^)' . + '|' . // contains no "::" + RE_IPV6_WORD . '(?::' . RE_IPV6_WORD . '){7}' . ')' + // NOTE: With PCRE 7.2+, we can combine the last two cases into one regex: + // RE_IPV6_WORD . '(?::((?(-1)|:))?' . RE_IPV6_WORD . '){1,6}(?(-2)|^)' + // This also improves regex concatenation by using relative references. ); // An IPv6 block is an IP address and a prefix (d1 to d128) define( 'RE_IPV6_BLOCK', RE_IPV6_ADD . '\/' . RE_IPV6_PREFIX ); diff --git a/tests/phpunit/includes/IPTest.php b/tests/phpunit/includes/IPTest.php index 8f8741cdbf..d9ec870a4a 100644 --- a/tests/phpunit/includes/IPTest.php +++ b/tests/phpunit/includes/IPTest.php @@ -39,17 +39,20 @@ class IPTest extends MediaWikiTestCase { $this->assertFalse( IP::isIPv6( 'fc:100:::' ), 'IPv6 ending with a ":::"' ); $this->assertFalse( IP::isIPv6( 'fc:300' ), 'IPv6 with only 2 words' ); $this->assertFalse( IP::isIPv6( 'fc:100:300' ), 'IPv6 with only 3 words' ); + $this->assertTrue( IP::isIPv6( 'fc:100::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e::' ) ); $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac::' ) ); + $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' ); $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0:1::' ), 'IPv6 with 9 words ending with "::"' ); $this->assertFalse( IP::isIPv6( ':::' ) ); $this->assertFalse( IP::isIPv6( '::0:' ), 'IPv6 ending in a lone ":"' ); + $this->assertTrue( IP::isIPv6( '::' ), 'IPv6 zero address' ); $this->assertTrue( IP::isIPv6( '::0' ) ); $this->assertTrue( IP::isIPv6( '::fc' ) ); @@ -59,18 +62,24 @@ class IPTest extends MediaWikiTestCase { $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1' ) ); $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e' ) ); $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e:ac' ) ); + $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' ); $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' ); $this->assertFalse( IP::isIPv6( ':fc::100' ), 'IPv6 starting with lone ":"' ); $this->assertFalse( IP::isIPv6( 'fc::100:' ), 'IPv6 ending with lone ":"' ); $this->assertFalse( IP::isIPv6( 'fc:::100' ), 'IPv6 with ":::" in the middle' ); + $this->assertTrue( IP::isIPv6( 'fc::100' ), 'IPv6 with "::" and 2 words' ); $this->assertTrue( IP::isIPv6( 'fc::100:a' ), 'IPv6 with "::" and 3 words' ); $this->assertTrue( IP::isIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' ) ); $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' ); $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e' ), 'IPv6 with "::" and 6 words' ); $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' ); + $this->assertTrue( IP::isIPv6( '2001::df'), 'IPv6 with "::" and 2 words' ); + $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df'), 'IPv6 with "::" and 5 words' ); + $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df:2'), 'IPv6 with "::" and 6 words' ); + $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' ); $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' ); @@ -111,6 +120,26 @@ class IPTest extends MediaWikiTestCase { $this->assertTrue( IP::isValid( $ip ) , "$ip is a valid IPv6 address" ); } } + // test with some abbreviations + $this->assertFalse( IP::isValid( ':fc:100::' ), 'IPv6 starting with lone ":"' ); + $this->assertFalse( IP::isValid( 'fc:100:::' ), 'IPv6 ending with a ":::"' ); + $this->assertFalse( IP::isValid( 'fc:300' ), 'IPv6 with only 2 words' ); + $this->assertFalse( IP::isValid( 'fc:100:300' ), 'IPv6 with only 3 words' ); + + $this->assertTrue( IP::isValid( 'fc:100::' ) ); + $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e::' ) ); + $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e:ac::' ) ); + + $this->assertTrue( IP::isValid( 'fc::100' ), 'IPv6 with "::" and 2 words' ); + $this->assertTrue( IP::isValid( 'fc::100:a' ), 'IPv6 with "::" and 3 words' ); + $this->assertTrue( IP::isValid( '2001::df'), 'IPv6 with "::" and 2 words' ); + $this->assertTrue( IP::isValid( '2001:5c0:1400:a::df'), 'IPv6 with "::" and 5 words' ); + $this->assertTrue( IP::isValid( '2001:5c0:1400:a::df:2'), 'IPv6 with "::" and 6 words' ); + $this->assertTrue( IP::isValid( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' ); + $this->assertTrue( IP::isValid( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' ); + + $this->assertFalse( IP::isValid( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' ); + $this->assertFalse( IP::isValid( 'fc:100:a:d:1:e:ac:0:1::' ), 'IPv6 with 9 words ending with "::"' ); } public function testInvalidIPs() { -- 2.20.1