1<?php 2 3class common_clientIP_test extends DokuWikiTest { 4 5 /** 6 * @var mixed[] $configs Possible values for $conf['trustedproxies']. 7 */ 8 private $configs = [ 9 ['::1', 'fe80::/10', '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'], 10 ]; 11 12 /** 13 * The data provider for clientIP() tests. 14 * 15 * @return mixed[][] Returns an array of test cases. 16 */ 17 public function client_ip_all_provider() : array { 18 // Malicious code in a header. 19 $bad = '<?php die("hacked"); ?>'; 20 21 // Letters A, B, C, D, E will be substitued with an IPv4 or IPv6 address. 22 $tests = [ 23 // A single IP with no other headers. 24 ['A', false, '', '', false, 'A'], 25 ['A', true, '', '', false, 'A'], 26 ['A', false, '', '', true, 'A'], 27 ['A', true, '', '', true, 'A'], 28 29 // A X-Real-IP header. 30 ['A', false, 'B', '', false, 'A'], 31 ['A', true, 'B', '', false, 'B,A'], 32 ['A', false, 'B', '', true, 'A'], 33 ['A', true, 'B', '', true, 'B'], 34 35 // An X-Forwarded-For header from an untrusted proxy. 36 ['A', false, 'B', 'C', false, 'A'], 37 ['A', true, 'B', 'C', false, 'B,A'], 38 ['A', false, 'B', 'C', true, 'A'], 39 ['A', true, 'B', 'C', true, 'B'], 40 41 // An X-Forwarded-For header from a trusted proxy. 42 ['D', false, 'B', 'C', false, 'C,D'], 43 ['D', true, 'B', 'C', false, 'B,C,D'], 44 ['D', false, 'B', 'C', true, 'C'], 45 ['D', true, 'B', 'C', true, 'B'], 46 47 // An X-Forwarded-For header with proxies from an untrusted proxy. 48 ['A', false, 'B', 'C,E', false, 'A'], 49 ['A', true, 'B', 'C,E', false, 'B,A'], 50 ['A', false, 'B', 'C,E', true, 'A'], 51 ['A', true, 'B', 'C,E', true, 'B'], 52 53 // An X-Forwarded-For header with untrusted proxies from a trusted proxy. 54 ['D', false, 'B', 'C,E', false, 'D'], 55 ['D', true, 'B', 'C,E', false, 'B,D'], 56 ['D', false, 'B', 'C,E', true, 'D'], 57 ['D', true, 'B', 'C,E', true, 'B'], 58 59 // An X-Forwarded-For header with an invalid proxy from a trusted proxy. 60 ['D', false, 'B', 'C,invalid,E', false, 'D'], 61 ['D', true, 'B', 'C,invalid,E', false, 'B,D'], 62 ['D', false, 'B', 'C,invalid,E', true, 'D'], 63 ['D', true, 'B', 'C,invalid,E', true, 'B'], 64 65 // Malicious X-Real-IP and X-Forwarded-For headers. 66 ['A', false, $bad, $bad, false, 'A'], 67 ['A', true, $bad, $bad, false, 'A'], 68 ['A', false, $bad, $bad, true, 'A'], 69 ['A', true, $bad, $bad, true, 'A'], 70 71 // Malicious remote address, X-Real-IP and X-Forwarded-For headers. 72 [$bad, false, $bad, $bad, false, '0.0.0.0'], 73 [$bad, true, $bad, $bad, false, '0.0.0.0'], 74 [$bad, false, $bad, $bad, true, '0.0.0.0'], 75 [$bad, true, $bad, $bad, true, '0.0.0.0'], 76 ]; 77 78 return $tests; 79 } 80 81 /** 82 * Test clientIP() with IPv6 addresses. 83 * 84 * @dataProvider client_ip_all_provider 85 * 86 * @param string $remoteAddr The TCP/IP remote IP address. 87 * @param bool $useRealIp True if using the X-Real-IP header is enabled in the config. 88 * @param string $realIp The X-Real-IP header. 89 * @param string $forwardedFor The X-Forwarded-For header. 90 * @param bool $single True to return the most likely client IP, false to return all candidates. 91 * @param string $expected The expected function result. 92 * 93 * @return void 94 */ 95 public function test_client_ip_v4(string $remoteAddr, bool $useRealIp, string $realIp, string $forwardedFor, bool $single, string $expected) : void { 96 global $conf; 97 98 $addresses = [ 99 'A' => '123.123.123.123', 100 'B' => '22.22.22.22', 101 'C' => '33.33.33.33', 102 'D' => '192.168.11.1', 103 'E' => '44.44.44.44', 104 ]; 105 106 $_SERVER['REMOTE_ADDR'] = str_replace(array_keys($addresses), array_values($addresses), $remoteAddr); 107 $_SERVER['HTTP_X_REAL_IP'] = str_replace(array_keys($addresses), array_values($addresses), $realIp); 108 $_SERVER['HTTP_X_FORWARDED_FOR'] = str_replace(array_keys($addresses), array_values($addresses), $forwardedFor); 109 $conf['realip'] = $useRealIp; 110 111 foreach ($this->configs as $config) { 112 $conf['trustedproxies'] = $config; 113 $this->assertEquals(str_replace(array_keys($addresses), array_values($addresses), $expected), clientIP($single)); 114 } 115 } 116 117 /** 118 * Test clientIP() with IPv6 addresses. 119 * 120 * @dataProvider client_ip_all_provider 121 * 122 * @param string $remoteAddr The TCP/IP remote IP address. 123 * @param bool $useRealIp True if using the X-Real-IP header is enabled in the config. 124 * @param string $realIp The X-Real-IP header. 125 * @param string $forwardedFor The X-Forwarded-For header. 126 * @param bool $single True to return the most likely client IP, false to return all candidates. 127 * @param string $expected The expected function result. 128 * 129 * @return void 130 */ 131 public function test_client_ip_v6(string $remoteAddr, bool $useRealIp, string $realIp, string $forwardedFor, bool $single, string $expected) : void { 132 global $conf; 133 134 $addresses = [ 135 'A' => '1234:1234:1234:1234:1234:1234:1234:1234', 136 'B' => '22:aa:22:bb:22:cc:22:dd', 137 'C' => '33:aa:33:bb:33:cc:33:dd', 138 'D' => '::1', 139 'E' => '44:aa:44:bb:44:cc:44:dd', 140 ]; 141 142 $_SERVER['REMOTE_ADDR'] = str_replace(array_keys($addresses), array_values($addresses), $remoteAddr); 143 $_SERVER['HTTP_X_REAL_IP'] = str_replace(array_keys($addresses), array_values($addresses), $realIp); 144 $_SERVER['HTTP_X_FORWARDED_FOR'] = str_replace(array_keys($addresses), array_values($addresses), $forwardedFor); 145 $conf['realip'] = $useRealIp; 146 147 foreach ($this->configs as $config) { 148 $conf['trustedproxies'] = $config; 149 $this->assertEquals(str_replace(array_keys($addresses), array_values($addresses), $expected), clientIP($single)); 150 } 151 } 152} 153