PageRenderTime 26ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/maintenance/tests/phpunit/includes/IPTest.php

https://github.com/bluelovers/mediawiki-trunk-phase3
PHP | 298 lines | 247 code | 24 blank | 27 comment | 0 complexity | 5b3e0c9ac1ff3ecc3f575d96c41eaa0d MD5 | raw file
  1. <?php
  2. /*
  3. * Tests for IP validity functions. Ported from /t/inc/IP.t by avar.
  4. */
  5. class IPTest extends PHPUnit_Framework_TestCase {
  6. // not sure it should be tested with boolean false. hashar 20100924
  7. public function testisIPAddress() {
  8. $this->assertFalse( IP::isIPAddress( false ), 'Boolean false is not an IP' );
  9. $this->assertFalse( IP::isIPAddress( true ), 'Boolean true is not an IP' );
  10. $this->assertFalse( IP::isIPAddress( "" ), 'Empty string is not an IP' );
  11. $this->assertFalse( IP::isIPAddress( 'abc' ), 'Garbage IP string' );
  12. $this->assertFalse( IP::isIPAddress( ':' ), 'Single ":" is not an IP' );
  13. $this->assertFalse( IP::isIPAddress( '2001:0DB8::A:1::1'), 'IPv6 with a double :: occurence' );
  14. $this->assertFalse( IP::isIPAddress( '2001:0DB8::A:1::'), 'IPv6 with a double :: occurence, last at end' );
  15. $this->assertFalse( IP::isIPAddress( '::2001:0DB8::5:1'), 'IPv6 with a double :: occurence, firt at beginning' );
  16. $this->assertFalse( IP::isIPAddress( '124.24.52' ), 'IPv4 not enough quads' );
  17. $this->assertFalse( IP::isIPAddress( '24.324.52.13' ), 'IPv4 out of range' );
  18. $this->assertFalse( IP::isIPAddress( '.24.52.13' ), 'IPv4 starts with period' );
  19. $this->assertFalse( IP::isIPAddress( 'fc:100:300' ), 'IPv6 with only 3 words' );
  20. $this->assertTrue( IP::isIPAddress( '::' ), 'RFC 4291 IPv6 Unspecified Address' );
  21. $this->assertTrue( IP::isIPAddress( '::1' ), 'RFC 4291 IPv6 Loopback Address' );
  22. $this->assertTrue( IP::isIPAddress( '74.24.52.13/20', 'IPv4 range' ) );
  23. $this->assertTrue( IP::isIPAddress( 'fc:100:a:d:1:e:ac:0/24' ), 'IPv6 range' );
  24. $this->assertTrue( IP::isIPAddress( 'fc::100:a:d:1:e:ac/96' ), 'IPv6 range with "::"' );
  25. $validIPs = array( 'fc:100::', 'fc:100:a:d:1:e:ac::', 'fc::100', '::fc:100:a:d:1:e:ac',
  26. '::fc', 'fc::100:a:d:1:e:ac', 'fc:100:a:d:1:e:ac:0', '124.24.52.13', '1.24.52.13' );
  27. foreach ( $validIPs as $ip ) {
  28. $this->assertTrue( IP::isIPAddress( $ip ), "$ip is a valid IP address" );
  29. }
  30. }
  31. public function testisIPv6() {
  32. $this->assertFalse( IP::isIPv6( ':fc:100::' ), 'IPv6 starting with lone ":"' );
  33. $this->assertFalse( IP::isIPv6( 'fc:100:::' ), 'IPv6 ending with a ":::"' );
  34. $this->assertFalse( IP::isIPv6( 'fc:300' ), 'IPv6 with only 2 words' );
  35. $this->assertFalse( IP::isIPv6( 'fc:100:300' ), 'IPv6 with only 3 words' );
  36. $this->assertTrue( IP::isIPv6( 'fc:100::' ) );
  37. $this->assertTrue( IP::isIPv6( 'fc:100:a::' ) );
  38. $this->assertTrue( IP::isIPv6( 'fc:100:a:d::' ) );
  39. $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1::' ) );
  40. $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e::' ) );
  41. $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac::' ) );
  42. $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' );
  43. $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0:1::' ), 'IPv6 with 9 words ending with "::"' );
  44. $this->assertFalse( IP::isIPv6( ':::' ) );
  45. $this->assertFalse( IP::isIPv6( '::0:' ), 'IPv6 ending in a lone ":"' );
  46. $this->assertTrue( IP::isIPv6( '::' ), 'IPv6 zero address' );
  47. $this->assertTrue( IP::isIPv6( '::0' ) );
  48. $this->assertTrue( IP::isIPv6( '::fc' ) );
  49. $this->assertTrue( IP::isIPv6( '::fc:100' ) );
  50. $this->assertTrue( IP::isIPv6( '::fc:100:a' ) );
  51. $this->assertTrue( IP::isIPv6( '::fc:100:a:d' ) );
  52. $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1' ) );
  53. $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e' ) );
  54. $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e:ac' ) );
  55. $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
  56. $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
  57. $this->assertFalse( IP::isIPv6( ':fc::100' ), 'IPv6 starting with lone ":"' );
  58. $this->assertFalse( IP::isIPv6( 'fc::100:' ), 'IPv6 ending with lone ":"' );
  59. $this->assertFalse( IP::isIPv6( 'fc:::100' ), 'IPv6 with ":::" in the middle' );
  60. $this->assertTrue( IP::isIPv6( 'fc::100' ), 'IPv6 with "::" and 2 words' );
  61. $this->assertTrue( IP::isIPv6( 'fc::100:a' ), 'IPv6 with "::" and 3 words' );
  62. $this->assertTrue( IP::isIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' ) );
  63. $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' );
  64. $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e' ), 'IPv6 with "::" and 6 words' );
  65. $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' );
  66. $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
  67. $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
  68. $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac:0' ) );
  69. }
  70. public function testisIPv4() {
  71. $this->assertFalse( IP::isIPv4( false ), 'Boolean false is not an IP' );
  72. $this->assertFalse( IP::isIPv4( true ), 'Boolean true is not an IP' );
  73. $this->assertFalse( IP::isIPv4( "" ), 'Empty string is not an IP' );
  74. $this->assertFalse( IP::isIPv4( 'abc' ) );
  75. $this->assertFalse( IP::isIPv4( ':' ) );
  76. $this->assertFalse( IP::isIPv4( '124.24.52' ), 'IPv4 not enough quads' );
  77. $this->assertFalse( IP::isIPv4( '24.324.52.13' ), 'IPv4 out of range' );
  78. $this->assertFalse( IP::isIPv4( '.24.52.13' ), 'IPv4 starts with period' );
  79. $this->assertTrue( IP::isIPv4( '124.24.52.13' ) );
  80. $this->assertTrue( IP::isIPv4( '1.24.52.13' ) );
  81. $this->assertTrue( IP::isIPv4( '74.24.52.13/20', 'IPv4 range' ) );
  82. }
  83. // tests isValid()
  84. public function testValidIPs() {
  85. foreach ( range( 0, 255 ) as $i ) {
  86. $a = sprintf( "%03d", $i );
  87. $b = sprintf( "%02d", $i );
  88. $c = sprintf( "%01d", $i );
  89. foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
  90. $ip = "$f.$f.$f.$f";
  91. $this->assertTrue( IP::isValid( $ip ) , "$ip is a valid IPv4 address" );
  92. }
  93. }
  94. foreach ( range( 0x0, 0xFFFF ) as $i ) {
  95. $a = sprintf( "%04x", $i );
  96. $b = sprintf( "%03x", $i );
  97. $c = sprintf( "%02x", $i );
  98. foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
  99. $ip = "$f:$f:$f:$f:$f:$f:$f:$f";
  100. $this->assertTrue( IP::isValid( $ip ) , "$ip is a valid IPv6 address" );
  101. }
  102. }
  103. }
  104. // tests isValid()
  105. public function testInvalidIPs() {
  106. // Out of range...
  107. foreach ( range( 256, 999 ) as $i ) {
  108. $a = sprintf( "%03d", $i );
  109. $b = sprintf( "%02d", $i );
  110. $c = sprintf( "%01d", $i );
  111. foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
  112. $ip = "$f.$f.$f.$f";
  113. $this->assertFalse( IP::isValid( $ip ), "$ip is not a valid IPv4 address" );
  114. }
  115. }
  116. foreach ( range( 'g', 'z' ) as $i ) {
  117. $a = sprintf( "%04s", $i );
  118. $b = sprintf( "%03s", $i );
  119. $c = sprintf( "%02s", $i );
  120. foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
  121. $ip = "$f:$f:$f:$f:$f:$f:$f:$f";
  122. $this->assertFalse( IP::isValid( $ip ) , "$ip is not a valid IPv6 address" );
  123. }
  124. }
  125. // Have CIDR
  126. $ipCIDRs = array(
  127. '212.35.31.121/32',
  128. '212.35.31.121/18',
  129. '212.35.31.121/24',
  130. '::ff:d:321:5/96',
  131. 'ff::d3:321:5/116',
  132. 'c:ff:12:1:ea:d:321:5/120',
  133. );
  134. foreach ( $ipCIDRs as $i ) {
  135. $this->assertFalse( IP::isValid( $i ),
  136. "$i is an invalid IP address because it is a block" );
  137. }
  138. // Incomplete/garbage
  139. $invalid = array(
  140. 'www.xn--var-xla.net',
  141. '216.17.184.G',
  142. '216.17.184.1.',
  143. '216.17.184',
  144. '216.17.184.',
  145. '256.17.184.1'
  146. );
  147. foreach ( $invalid as $i ) {
  148. $this->assertFalse( IP::isValid( $i ), "$i is an invalid IP address" );
  149. }
  150. }
  151. // tests isValidBlock()
  152. public function testValidBlocks() {
  153. $valid = array(
  154. '116.17.184.5/32',
  155. '0.17.184.5/30',
  156. '16.17.184.1/24',
  157. '30.242.52.14/1',
  158. '10.232.52.13/8',
  159. '30.242.52.14/0',
  160. '::e:f:2001/96',
  161. '::c:f:2001/128',
  162. '::10:f:2001/70',
  163. '::fe:f:2001/1',
  164. '::6d:f:2001/8',
  165. '::fe:f:2001/0',
  166. );
  167. foreach ( $valid as $i ) {
  168. $this->assertTrue( IP::isValidBlock( $i ), "$i is a valid IP block" );
  169. }
  170. }
  171. // tests isValidBlock()
  172. public function testInvalidBlocks() {
  173. $invalid = array(
  174. '116.17.184.5/33',
  175. '0.17.184.5/130',
  176. '16.17.184.1/-1',
  177. '10.232.52.13/*',
  178. '7.232.52.13/ab',
  179. '11.232.52.13/',
  180. '::e:f:2001/129',
  181. '::c:f:2001/228',
  182. '::10:f:2001/-1',
  183. '::6d:f:2001/*',
  184. '::86:f:2001/ab',
  185. '::23:f:2001/',
  186. );
  187. foreach ( $invalid as $i ) {
  188. $this->assertFalse( IP::isValidBlock( $i ), "$i is not a valid IP block" );
  189. }
  190. }
  191. // test wrapper around ip2long which might return -1 or false depending on PHP version
  192. public function testip2longWrapper() {
  193. // fixme : add more tests ?
  194. $this->assertEquals( pow(2,32) - 1, IP::toUnsigned( '255.255.255.255' ));
  195. $i = 'IN.VA.LI.D';
  196. $this->assertFalse( IP::toUnSigned( $i ) );
  197. }
  198. // tests isPublic()
  199. public function testPrivateIPs() {
  200. $private = array( 'fc::3', 'fc::ff', '::1', '10.0.0.1', '172.16.0.1', '192.168.0.1' );
  201. foreach ( $private as $p ) {
  202. $this->assertFalse( IP::isPublic( $p ), "$p is not a public IP address" );
  203. }
  204. }
  205. // Private wrapper used to test CIDR Parsing.
  206. private function assertFalseCIDR( $CIDR, $msg='' ) {
  207. $ff = array( false, false );
  208. $this->assertEquals( $ff, IP::parseCIDR( $CIDR ), $msg );
  209. }
  210. // Private wrapper to test network shifting using only dot notation
  211. private function assertNet( $expected, $CIDR ) {
  212. $parse = IP::parseCIDR( $CIDR );
  213. $this->assertEquals( $expected, long2ip( $parse[0] ), "network shifting $CIDR" );
  214. }
  215. public function testHexToQuad() {
  216. $this->assertEquals( '0.0.0.1' , IP::hexToQuad( '00000001' ) );
  217. $this->assertEquals( '255.0.0.0' , IP::hexToQuad( 'FF000000' ) );
  218. $this->assertEquals( '255.255.255.255', IP::hexToQuad( 'FFFFFFFF' ) );
  219. $this->assertEquals( '10.188.222.255' , IP::hexToQuad( '0ABCDEFF' ) );
  220. // hex not left-padded...
  221. $this->assertEquals( '0.0.0.0' , IP::hexToQuad( '0' ) );
  222. $this->assertEquals( '0.0.0.1' , IP::hexToQuad( '1' ) );
  223. $this->assertEquals( '0.0.0.255' , IP::hexToQuad( 'FF' ) );
  224. $this->assertEquals( '0.0.255.0' , IP::hexToQuad( 'FF00' ) );
  225. }
  226. public function testHexToOctet() {
  227. $this->assertEquals( '0:0:0:0:0:0:0:1',
  228. IP::hexToOctet( '00000000000000000000000000000001' ) );
  229. $this->assertEquals( '0:0:0:0:0:0:FF:3',
  230. IP::hexToOctet( '00000000000000000000000000FF0003' ) );
  231. $this->assertEquals( '0:0:0:0:0:0:FF00:6',
  232. IP::hexToOctet( '000000000000000000000000FF000006' ) );
  233. $this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF',
  234. IP::hexToOctet( '000000000000000000000000FCCFFAFF' ) );
  235. $this->assertEquals( 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',
  236. IP::hexToOctet( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' ) );
  237. // hex not left-padded...
  238. $this->assertEquals( '0:0:0:0:0:0:0:0' , IP::hexToOctet( '0' ) );
  239. $this->assertEquals( '0:0:0:0:0:0:0:1' , IP::hexToOctet( '1' ) );
  240. $this->assertEquals( '0:0:0:0:0:0:0:FF' , IP::hexToOctet( 'FF' ) );
  241. $this->assertEquals( '0:0:0:0:0:0:0:FFD0' , IP::hexToOctet( 'FFD0' ) );
  242. $this->assertEquals( '0:0:0:0:0:0:FA00:0' , IP::hexToOctet( 'FA000000' ) );
  243. $this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF', IP::hexToOctet( 'FCCFFAFF' ) );
  244. }
  245. /*
  246. * IP::parseCIDR() returns an array containing a signed IP address
  247. * representing the network mask and the bit mask.
  248. */
  249. function testCIDRParsing() {
  250. $this->assertFalseCIDR( '192.0.2.0' , "missing mask" );
  251. $this->assertFalseCIDR( '192.0.2.0/', "missing bitmask" );
  252. // Verify if statement
  253. $this->assertFalseCIDR( '256.0.0.0/32', "invalid net" );
  254. $this->assertFalseCIDR( '192.0.2.0/AA', "mask not numeric" );
  255. $this->assertFalseCIDR( '192.0.2.0/-1', "mask < 0" );
  256. $this->assertFalseCIDR( '192.0.2.0/33', "mask > 32" );
  257. // Check internal logic
  258. # 0 mask always result in array(0,0)
  259. $this->assertEquals( array( 0, 0 ), IP::parseCIDR('192.0.0.2/0') );
  260. $this->assertEquals( array( 0, 0 ), IP::parseCIDR('0.0.0.0/0') );
  261. $this->assertEquals( array( 0, 0 ), IP::parseCIDR('255.255.255.255/0') );
  262. // FIXME : add more tests.
  263. # This part test network shifting
  264. $this->assertNet( '192.0.0.0' , '192.0.0.2/24' );
  265. $this->assertNet( '192.168.5.0', '192.168.5.13/24');
  266. $this->assertNet( '10.0.0.160' , '10.0.0.161/28' );
  267. $this->assertNet( '10.0.0.0' , '10.0.0.3/28' );
  268. $this->assertNet( '10.0.0.0' , '10.0.0.3/30' );
  269. $this->assertNet( '10.0.0.4' , '10.0.0.4/30' );
  270. $this->assertNet( '172.17.32.0', '172.17.35.48/21' );
  271. $this->assertNet( '10.128.0.0' , '10.135.0.0/9' );
  272. $this->assertNet( '134.0.0.0' , '134.0.5.1/8' );
  273. }
  274. }