17caad012SAndreas Gohr<?php 27caad012SAndreas Gohr 37caad012SAndreas Gohrnamespace dokuwiki\test; 47caad012SAndreas Gohr 57caad012SAndreas Gohruse dokuwiki\Input\Input; 67caad012SAndreas Gohruse dokuwiki\Ip; 77caad012SAndreas Gohr 87caad012SAndreas Gohrclass IpTest extends \DokuWikiTest { 97caad012SAndreas Gohr 107caad012SAndreas Gohr /** 117caad012SAndreas Gohr * The data provider for ipToNumber() tests. 127caad012SAndreas Gohr * 137caad012SAndreas Gohr * @return mixed[][] Returns an array of test cases. 147caad012SAndreas Gohr */ 157caad012SAndreas Gohr public function ip_to_number_provider() : array 167caad012SAndreas Gohr { 177caad012SAndreas Gohr $tests = [ 187caad012SAndreas Gohr ['127.0.0.1', 4, 0x00000000, 0x7f000001], 197caad012SAndreas Gohr ['::127.0.0.1', 6, 0x00000000, 0x7f000001], 207caad012SAndreas Gohr ['::1', 6, 0x00000000, 0x00000001], 217caad012SAndreas Gohr ['38AF:3033:AA39:CDE3:1A46:094C:44ED:5300', 6, 0x38AF3033AA39CDE3, 0x1A46094C44ED5300], 22e7cd6878SWillForan ['0000:0000:0000:0000:0000:0000:0000:0000', 6, 0, 0], 237caad012SAndreas Gohr ['193.53.125.7', 4, 0x00000000, 0xC1357D07], 242f70db90SWillForan // NOTE: wrap around! 0xFFFFFFFFFFFFFFFE seen as -2 252f70db90SWillForan ['7FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE', 6, 0x7FFFFFFFFFFFFFFF, -2], 267caad012SAndreas Gohr ]; 277caad012SAndreas Gohr 282f70db90SWillForan // float loses percision and give confusing test results! 292f70db90SWillForan // sprintf("%.0f",0x7FFFFFFFFFFFFFFF) == sprintf("%.0f",0x7FFFFFFFFFFFFF00) 302f70db90SWillForan // using string of decimal values instead 312f70db90SWillForan if(PHP_INT_SIZE == 4) { 322f70db90SWillForan $tests = [ 332f70db90SWillForan ['127.0.0.1', 4, '0', '2130706433'], 342f70db90SWillForan ['::127.0.0.1', 6, '0','2130706433'], 352f70db90SWillForan ['::1', 6, '0', '1'], 362f70db90SWillForan ['0000:0000:0000:0000:0000:0000:0000:0000', 6, '0', '0'], 372f70db90SWillForan ['193.53.125.7', 4, '0', '3241508103'], 382f70db90SWillForan ['7FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE', 6, '9223372036854775807', '18446744073709551614'], 392f70db90SWillForan ['38AF:3033:AA39:CDE3:1A46:094C:44ED:5300', 6, '4084536385505709539', '1893210916534440704'] 402f70db90SWillForan ]; 412f70db90SWillForan } 427caad012SAndreas Gohr return $tests; 437caad012SAndreas Gohr } 447caad012SAndreas Gohr 457caad012SAndreas Gohr /** 467caad012SAndreas Gohr * Test ipToNumber(). 477caad012SAndreas Gohr * 487caad012SAndreas Gohr * @dataProvider ip_to_number_provider 497caad012SAndreas Gohr * 507caad012SAndreas Gohr * @param string $ip The IP address to convert. 517caad012SAndreas Gohr * @param int $version The IP version, either 4 or 6. 527caad012SAndreas Gohr * @param int $upper The upper 64 bits of the IP. 537caad012SAndreas Gohr * @param int $lower The lower 64 bits of the IP. 547caad012SAndreas Gohr * 557caad012SAndreas Gohr * @return void 562f70db90SWillForan * 572f70db90SWillForan * Note: $upper and $lower are likley 'float' instead of 'int' for large values. 582f70db90SWillForan * The more accurate hint 'int|float' is not supported in php7.4. 597caad012SAndreas Gohr */ 602f70db90SWillForan public function test_ip_to_number(string $ip, int $version, $upper, $lower): void 617caad012SAndreas Gohr { 627caad012SAndreas Gohr $result = Ip::ipToNumber($ip); 637caad012SAndreas Gohr 642f70db90SWillForan // force output of ipv4 to string for easy compare 652f70db90SWillForan if(PHP_INT_SIZE == 4 and !is_string($result['upper']) ) { 662f70db90SWillForan $result['upper'] = sprintf("%.0f", $result['upper']); 672f70db90SWillForan $result['lower'] = sprintf("%.0f", $result['lower']); 68e7cd6878SWillForan } 69e7cd6878SWillForan 707caad012SAndreas Gohr $this->assertSame($version, $result['version']); 717caad012SAndreas Gohr $this->assertSame($upper, $result['upper']); 727caad012SAndreas Gohr $this->assertSame($lower, $result['lower']); 737caad012SAndreas Gohr } 747caad012SAndreas Gohr 757caad012SAndreas Gohr /** 767caad012SAndreas Gohr * The data provider for test_ip_in_range(). 777caad012SAndreas Gohr * 787caad012SAndreas Gohr * @return mixed[][] Returns an array of test cases. 797caad012SAndreas Gohr */ 807caad012SAndreas Gohr public function ip_in_range_provider(): array 817caad012SAndreas Gohr { 827caad012SAndreas Gohr $tests = [ 837caad012SAndreas Gohr ['192.168.11.2', '192.168.0.0/16', true], 847caad012SAndreas Gohr ['192.168.11.2', '192.168.64.1/16', true], 857caad012SAndreas Gohr ['192.168.11.2', '192.168.64.1/18', false], 867caad012SAndreas Gohr ['192.168.11.2', '192.168.11.0/20', true], 877caad012SAndreas Gohr ['127.0.0.1', '127.0.0.0/7', true], 887caad012SAndreas Gohr ['127.0.0.1', '127.0.0.0/8', true], 897caad012SAndreas Gohr ['127.0.0.1', '127.200.0.0/8', true], 907caad012SAndreas Gohr ['127.0.0.1', '127.200.0.0/9', false], 917caad012SAndreas Gohr ['127.0.0.1', '127.0.0.0/31', true], 927caad012SAndreas Gohr ['127.0.0.1', '127.0.0.0/32', false], 937caad012SAndreas Gohr ['127.0.0.1', '127.0.0.1/32', true], 947caad012SAndreas Gohr ['1111:2222:3333:4444:5555:6666:7777:8888', '1110::/12', true], 957caad012SAndreas Gohr ['1110:2222:3333:4444:5555:6666:7777:8888', '1110::/12', true], 967caad012SAndreas Gohr ['1100:2222:3333:4444:5555:6666:7777:8888', '1110::/12', false], 977caad012SAndreas Gohr ['1111:2222:3333:4444:5555:6666:7777:8888', '1111:2222:3300::/40', true], 987caad012SAndreas Gohr ['1111:2222:3333:4444:5555:6666:7777:8888', '1111:2222:3200::/40', false], 997caad012SAndreas Gohr ['1111:2222:3333:4444:5555:6666:7777:8888', '1111:2222:3333:4444:5555:6666:7777:8889/127', true], 1007caad012SAndreas Gohr ['1111:2222:3333:4444:5555:6666:7777:8888', '1111:2222:3333:4444:5555:6666:7777:8889/128', false], 1017caad012SAndreas Gohr ['1111:2222:3333:4444:5555:6666:7777:8889', '1111:2222:3333:4444:5555:6666:7777:8889/128', true], 1027caad012SAndreas Gohr ['abcd:ef0a:bcde:f0ab:cdef:0abc:def0:abcd', 'abcd:ef0a:bcde:f0ab:cdef:0abc:def0:abcd/128', true], 1037caad012SAndreas Gohr ['abcd:ef0a:bcde:f0ab:cdef:0abc:def0:abce', 'abcd:ef0a:bcde:f0ab:cdef:0abc:def0:abcd/128', false], 1047caad012SAndreas Gohr ]; 1057caad012SAndreas Gohr 1067caad012SAndreas Gohr return $tests; 1077caad012SAndreas Gohr } 1087caad012SAndreas Gohr 1097caad012SAndreas Gohr /** 1107caad012SAndreas Gohr * Test ipInRange(). 1117caad012SAndreas Gohr * 1127caad012SAndreas Gohr * @dataProvider ip_in_range_provider 1137caad012SAndreas Gohr * 1147caad012SAndreas Gohr * @param string $ip The IP to test. 1157caad012SAndreas Gohr * @param string $range The IP range to test against. 1167caad012SAndreas Gohr * @param bool $expected The expected result from ipInRange(). 1177caad012SAndreas Gohr * 1187caad012SAndreas Gohr * @return void 1197caad012SAndreas Gohr */ 1207caad012SAndreas Gohr public function test_ip_in_range(string $ip, string $range, bool $expected): void 1217caad012SAndreas Gohr { 1227caad012SAndreas Gohr $result = Ip::ipInRange($ip, $range); 1237caad012SAndreas Gohr 1247caad012SAndreas Gohr $this->assertSame($expected, $result); 1257caad012SAndreas Gohr } 1267caad012SAndreas Gohr 1277caad012SAndreas Gohr /** 128*40981bccSAndreas Gohr * The data provider for test_ip_in_range_invalid_mask(). 129*40981bccSAndreas Gohr * 130*40981bccSAndreas Gohr * @return string[][] Returns an array of [ip, range] with an invalid mask. 131*40981bccSAndreas Gohr */ 132*40981bccSAndreas Gohr public function ip_in_range_invalid_mask_provider(): array 133*40981bccSAndreas Gohr { 134*40981bccSAndreas Gohr return [ 135*40981bccSAndreas Gohr // Non-numeric mask: would throw a TypeError on the "+= 96" IPv4 path. 136*40981bccSAndreas Gohr ['127.0.0.1', '10.0.0.0/abc'], 137*40981bccSAndreas Gohr // Empty mask. 138*40981bccSAndreas Gohr ['127.0.0.1', '10.0.0.0/'], 139*40981bccSAndreas Gohr // Negative mask: would pass the "> 128" check and match every IPv4. 140*40981bccSAndreas Gohr ['1.2.3.4', '10.0.0.0/-1'], 141*40981bccSAndreas Gohr ['1.2.3.4', '10.0.0.0/-5'], 142*40981bccSAndreas Gohr ]; 143*40981bccSAndreas Gohr } 144*40981bccSAndreas Gohr 145*40981bccSAndreas Gohr /** 146*40981bccSAndreas Gohr * Test that ipInRange() rejects an invalid mask with an Exception rather 147*40981bccSAndreas Gohr * than a TypeError or an over-broad match. 148*40981bccSAndreas Gohr * 149*40981bccSAndreas Gohr * @dataProvider ip_in_range_invalid_mask_provider 150*40981bccSAndreas Gohr * 151*40981bccSAndreas Gohr * @param string $ip The IP to test. 152*40981bccSAndreas Gohr * @param string $range The IP range with the invalid mask. 153*40981bccSAndreas Gohr * 154*40981bccSAndreas Gohr * @return void 155*40981bccSAndreas Gohr */ 156*40981bccSAndreas Gohr public function test_ip_in_range_invalid_mask(string $ip, string $range): void 157*40981bccSAndreas Gohr { 158*40981bccSAndreas Gohr $this->expectException(\Exception::class); 159*40981bccSAndreas Gohr Ip::ipInRange($ip, $range); 160*40981bccSAndreas Gohr } 161*40981bccSAndreas Gohr 162*40981bccSAndreas Gohr /** 1637caad012SAndreas Gohr * Data provider for test_ip_matches(). 1647caad012SAndreas Gohr * 1657caad012SAndreas Gohr * @return mixed[][] Returns an array of test cases. 1667caad012SAndreas Gohr */ 1677caad012SAndreas Gohr public function ip_matches_provider(): array 1687caad012SAndreas Gohr { 1697caad012SAndreas Gohr // Tests for a CIDR range. 1707caad012SAndreas Gohr $rangeTests = $this->ip_in_range_provider(); 1717caad012SAndreas Gohr 1727caad012SAndreas Gohr // Tests for an exact IP match. 1737caad012SAndreas Gohr $exactTests = [ 1747caad012SAndreas Gohr ['127.0.0.1', '127.0.0.1', true], 1757caad012SAndreas Gohr ['127.0.0.1', '127.0.0.0', false], 1767caad012SAndreas Gohr ['aaaa:bbbb:cccc:dddd:eeee::', 'aaaa:bbbb:cccc:dddd:eeee:0000:0000:0000', true], 1777caad012SAndreas Gohr ['aaaa:bbbb:cccc:dddd:eeee:0000:0000:0000', 'aaaa:bbbb:cccc:dddd:eeee::', true], 1787caad012SAndreas Gohr ['aaaa:bbbb:0000:0000:0000:0000:0000:0001', 'aaaa:bbbb::1', true], 1797caad012SAndreas Gohr ['aaaa:bbbb::0001', 'aaaa:bbbb::1', true], 1807caad012SAndreas Gohr ['aaaa:bbbb::0001', 'aaaa:bbbb::', false], 1817caad012SAndreas Gohr ['::ffff:127.0.0.1', '127.0.0.1', false], 1827caad012SAndreas Gohr ['::ffff:127.0.0.1', '::0:ffff:127.0.0.1', true], 1837caad012SAndreas Gohr ]; 1847caad012SAndreas Gohr 185*40981bccSAndreas Gohr // Invalid masks must degrade to "no match" instead of a fatal error 186*40981bccSAndreas Gohr // (non-numeric mask) or an over-broad match (negative mask). 187*40981bccSAndreas Gohr $invalidMaskTests = [ 188*40981bccSAndreas Gohr ['127.0.0.1', '10.0.0.0/abc', false], 189*40981bccSAndreas Gohr ['127.0.0.1', '10.0.0.0/', false], 190*40981bccSAndreas Gohr ['1.2.3.4', '10.0.0.0/-1', false], 191*40981bccSAndreas Gohr ['1.2.3.4', '10.0.0.0/-5', false], 192*40981bccSAndreas Gohr ]; 1937caad012SAndreas Gohr 194*40981bccSAndreas Gohr 195*40981bccSAndreas Gohr return array_merge($rangeTests, $exactTests, $invalidMaskTests); 1967caad012SAndreas Gohr } 1977caad012SAndreas Gohr 1987caad012SAndreas Gohr /** 1997caad012SAndreas Gohr * Test ipMatches(). 2007caad012SAndreas Gohr * 2017caad012SAndreas Gohr * @dataProvider ip_matches_provider 2027caad012SAndreas Gohr * 2037caad012SAndreas Gohr * @param string $ip The IP to test. 2047caad012SAndreas Gohr * @param string $ipOrRange The IP or IP range to test against. 2057caad012SAndreas Gohr * @param bool $expected The expeced result from ipMatches(). 2067caad012SAndreas Gohr * 2077caad012SAndreas Gohr * @return void 2087caad012SAndreas Gohr */ 2097caad012SAndreas Gohr public function test_ip_matches(string $ip, string $ipOrRange, bool $expected): void 2107caad012SAndreas Gohr { 2117caad012SAndreas Gohr $result = Ip::ipMatches($ip, $ipOrRange); 2127caad012SAndreas Gohr 2137caad012SAndreas Gohr $this->assertSame($expected, $result); 2147caad012SAndreas Gohr } 2157caad012SAndreas Gohr 2167caad012SAndreas Gohr /** 2177caad012SAndreas Gohr * Data provider for proxyIsTrusted(). 2187caad012SAndreas Gohr * 2197caad012SAndreas Gohr * @return mixed[][] Returns an array of test cases. 2207caad012SAndreas Gohr */ 2217caad012SAndreas Gohr public function proxy_is_trusted_provider(): array 2227caad012SAndreas Gohr { 2237caad012SAndreas Gohr // The new default configuration value. 2247caad012SAndreas Gohr $default = ['::1', 'fe80::/10', '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']; 2257caad012SAndreas Gohr 2267caad012SAndreas Gohr // Adding some custom trusted proxies. 2277caad012SAndreas Gohr $custom = array_merge($default, ['1.2.3.4', '1122::', '3.0.0.1/8', '1111:2222::/32']); 2287caad012SAndreas Gohr 2297caad012SAndreas Gohr $tests = [ 2307caad012SAndreas Gohr // Empty configuration. 2317caad012SAndreas Gohr ['', '127.0.0.1', false], 2327caad012SAndreas Gohr 2337caad012SAndreas Gohr // Configuration with an array of IPs/CIDRs. 2347caad012SAndreas Gohr [$default, '127.0.0.1', true], 2357caad012SAndreas Gohr [$default, '127.1.2.3', true], 2367caad012SAndreas Gohr [$default, '10.1.2.3', true], 2377caad012SAndreas Gohr [$default, '11.1.2.3', false], 2387caad012SAndreas Gohr [$default, '172.16.0.1', true], 2397caad012SAndreas Gohr [$default, '172.160.0.1', false], 2407caad012SAndreas Gohr [$default, '172.31.255.255', true], 2417caad012SAndreas Gohr [$default, '172.32.0.0', false], 2427caad012SAndreas Gohr [$default, '172.200.0.0', false], 2437caad012SAndreas Gohr [$default, '192.168.2.3', true], 2447caad012SAndreas Gohr [$default, '192.169.1.2', false], 2457caad012SAndreas Gohr [$default, '::1', true], 2467caad012SAndreas Gohr [$default, '0000:0000:0000:0000:0000:0000:0000:0001', true], 2477caad012SAndreas Gohr 2487caad012SAndreas Gohr // With custom proxies set. 2497caad012SAndreas Gohr [$custom, '127.0.0.1', true], 2507caad012SAndreas Gohr [$custom, '1.2.3.4', true], 2517caad012SAndreas Gohr [$custom, '3.0.1.2', true], 2527caad012SAndreas Gohr [$custom, '1122::', true], 2537caad012SAndreas Gohr [$custom, '1122:0000:0000:0000:0000:0000:0000:0000', true], 2547caad012SAndreas Gohr [$custom, '1111:2223::', false], 2557caad012SAndreas Gohr [$custom, '1111:2222::', true], 2567caad012SAndreas Gohr [$custom, '1111:2222:3333::', true], 2577caad012SAndreas Gohr [$custom, '1111:2222:3333::1', true], 2587caad012SAndreas Gohr ]; 2597caad012SAndreas Gohr 2607caad012SAndreas Gohr return $tests; 2617caad012SAndreas Gohr } 2627caad012SAndreas Gohr 2637caad012SAndreas Gohr /** 2647caad012SAndreas Gohr * Test proxyIsTrusted(). 2657caad012SAndreas Gohr * 2667caad012SAndreas Gohr * @dataProvider proxy_is_trusted_provider 2677caad012SAndreas Gohr * 2687caad012SAndreas Gohr * @param string|string[] $config The value for $conf[trustedproxies]. 2697caad012SAndreas Gohr * @param string $ip The proxy IP to test. 2707caad012SAndreas Gohr * @param bool $expected The expected result from proxyIsTrusted(). 2717caad012SAndreas Gohr */ 2727caad012SAndreas Gohr public function test_proxy_is_trusted($config, string $ip, bool $expected): void 2737caad012SAndreas Gohr { 2747caad012SAndreas Gohr global $conf; 2757caad012SAndreas Gohr $conf['trustedproxies'] = $config; 2767caad012SAndreas Gohr 2777caad012SAndreas Gohr $result = Ip::proxyIsTrusted($ip); 2787caad012SAndreas Gohr 2797caad012SAndreas Gohr $this->assertSame($expected, $result); 2807caad012SAndreas Gohr } 2817caad012SAndreas Gohr 2827caad012SAndreas Gohr /** 2837caad012SAndreas Gohr * Data provider for test_forwarded_for(). 2847caad012SAndreas Gohr * 2857caad012SAndreas Gohr * @return mixed[][] Returns an array of test cases. 2867caad012SAndreas Gohr */ 2877caad012SAndreas Gohr public function forwarded_for_provider(): array 2887caad012SAndreas Gohr { 2897caad012SAndreas Gohr // The new default configuration value. 2907caad012SAndreas Gohr $default = ['::1', 'fe80::/10', '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']; 2917caad012SAndreas Gohr 2927caad012SAndreas Gohr // Adding some custom trusted proxies. 2937caad012SAndreas Gohr $custom = array_merge($default, ['1.2.3.4', '1122::', '3.0.0.1/8', '1111:2222::/32']); 2947caad012SAndreas Gohr 2957caad012SAndreas Gohr $tests = [ 2967caad012SAndreas Gohr // Empty config value should always return empty array. 2977caad012SAndreas Gohr [[], '', '127.0.0.1', []], 2987caad012SAndreas Gohr [[], '127.0.0.1', '127.0.0.1', []], 2997caad012SAndreas Gohr 3007caad012SAndreas Gohr // The new default configuration. 3017caad012SAndreas Gohr [$default, '', '127.0.0.1', []], 3027caad012SAndreas Gohr [$default, '1.2.3.4', '127.0.0.1', ['1.2.3.4', '127.0.0.1']], 3037caad012SAndreas Gohr [$default, '1.2.3.4', '192.168.1.1', ['1.2.3.4', '192.168.1.1']], 3047caad012SAndreas Gohr [$default, '1.2.3.4,172.16.0.1', '192.168.1.1', ['1.2.3.4', '172.16.0.1', '192.168.1.1']], 3057caad012SAndreas Gohr [$default, '1.2.3.4,172.16.0.1', '::1', ['1.2.3.4', '172.16.0.1', '::1']], 3067caad012SAndreas Gohr [$default, '1.2.3.4,172.16.0.1', '::0001', ['1.2.3.4', '172.16.0.1', '::0001']], 3077caad012SAndreas Gohr 3087caad012SAndreas Gohr // Directly from an untrusted proxy. 3097caad012SAndreas Gohr [$default, '', '127.0.0.1', []], 3107caad012SAndreas Gohr [$default, '1.2.3.4', '11.22.33.44', []], 3117caad012SAndreas Gohr [$default, '::1', '11.22.33.44', []], 3127caad012SAndreas Gohr [$default, '::1', '::2', []], 3137caad012SAndreas Gohr 3147caad012SAndreas Gohr // From a trusted proxy, but via an untrusted proxy. 3157caad012SAndreas Gohr [$default, '1.2.3.4,11.22.33.44,172.16.0.1', '192.168.1.1', []], 3167caad012SAndreas Gohr [$default, '1.2.3.4,::2,172.16.0.1', '::1', []], 3177caad012SAndreas Gohr 3187caad012SAndreas Gohr // A custom configuration. 3197caad012SAndreas Gohr [$custom, '', '127.0.0.1', []], 3207caad012SAndreas Gohr [$custom, '1.2.3.4', '127.0.0.1', ['1.2.3.4', '127.0.0.1']], 3217caad012SAndreas Gohr [$custom, '1.2.3.4', '192.168.1.1', ['1.2.3.4', '192.168.1.1']], 3227caad012SAndreas Gohr [$custom, '1.2.3.4,172.16.0.1', '192.168.1.1', ['1.2.3.4', '172.16.0.1', '192.168.1.1']], 3237caad012SAndreas Gohr [$custom, '1.2.3.4,172.16.0.1', '::1', ['1.2.3.4', '172.16.0.1', '::1']], 3247caad012SAndreas Gohr [$custom, '1.2.3.4,172.16.0.1', '::0001', ['1.2.3.4', '172.16.0.1', '::0001']], 3257caad012SAndreas Gohr 3267caad012SAndreas Gohr // Directly from an untrusted proxy. 3277caad012SAndreas Gohr [$custom, '', '127.0.0.1', []], 3287caad012SAndreas Gohr [$custom, '1.2.3.4', '11.22.33.44', []], 3297caad012SAndreas Gohr [$custom, '::1', '11.22.33.44', []], 3307caad012SAndreas Gohr [$custom, '::1', '::2', []], 3317caad012SAndreas Gohr 3327caad012SAndreas Gohr // From a trusted proxy, but via an untrusted proxy. 3337caad012SAndreas Gohr [$custom, '1.2.3.4,11.22.33.44,172.16.0.1', '192.168.1.1', []], 3347caad012SAndreas Gohr [$custom, '1.2.3.4,::2,172.16.0.1', '::1', []], 3357caad012SAndreas Gohr 3367caad012SAndreas Gohr // Via a custom proxy. 3377caad012SAndreas Gohr [$custom, '11.2.3.4,3.1.2.3,172.16.0.1', '192.168.1.1', ['11.2.3.4', '3.1.2.3', '172.16.0.1', '192.168.1.1']], 3387caad012SAndreas Gohr [$custom, '11.2.3.4,1122::,172.16.0.1', '3.0.0.1', ['11.2.3.4', '1122::', '172.16.0.1', '3.0.0.1']], 3397caad012SAndreas Gohr [$custom, '11.2.3.4,1122::,172.16.0.1', '1111:2222:3333::', ['11.2.3.4', '1122::', '172.16.0.1', '1111:2222:3333::']], 3407caad012SAndreas Gohr ]; 3417caad012SAndreas Gohr 3427caad012SAndreas Gohr return $tests; 3437caad012SAndreas Gohr } 3447caad012SAndreas Gohr 3457caad012SAndreas Gohr /** 3467caad012SAndreas Gohr * Test forwardedFor(). 3477caad012SAndreas Gohr * 3487caad012SAndreas Gohr * @dataProvider forwarded_for_provider 3497caad012SAndreas Gohr * 3507caad012SAndreas Gohr * @param string|string[] $config The trustedproxies config value. 3517caad012SAndreas Gohr * @param string $header The X-Forwarded-For header value. 3527caad012SAndreas Gohr * @param string $remoteAddr The TCP/IP peer address. 3537caad012SAndreas Gohr * @param array $expected The expected result from forwardedFor(). 3547caad012SAndreas Gohr * 3557caad012SAndreas Gohr * @return void 3567caad012SAndreas Gohr */ 3577caad012SAndreas Gohr public function test_forwarded_for($config, string $header, string $remoteAddr, array $expected): void 3587caad012SAndreas Gohr { 3597caad012SAndreas Gohr /* @var Input $INPUT */ 3607caad012SAndreas Gohr global $INPUT, $conf; 3617caad012SAndreas Gohr 3627caad012SAndreas Gohr $conf['trustedproxies'] = $config; 3637caad012SAndreas Gohr $INPUT->server->set('HTTP_X_FORWARDED_FOR', $header); 3647caad012SAndreas Gohr $INPUT->server->set('REMOTE_ADDR', $remoteAddr); 3657caad012SAndreas Gohr 3667caad012SAndreas Gohr $result = Ip::forwardedFor(); 3677caad012SAndreas Gohr 3687caad012SAndreas Gohr $this->assertSame($expected, $result); 3697caad012SAndreas Gohr } 3707caad012SAndreas Gohr 3717caad012SAndreas Gohr /** 3727caad012SAndreas Gohr * Data provider for test_is_ssl(). 3737caad012SAndreas Gohr * 3747caad012SAndreas Gohr * @return mixed[][] Returns an array of test cases. 3757caad012SAndreas Gohr */ 3767caad012SAndreas Gohr public function is_ssl_provider(): array 3777caad012SAndreas Gohr { 3787caad012SAndreas Gohr // The new default configuration value. 3797caad012SAndreas Gohr $default = ['::1', 'fe80::/10', '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']; 3807caad012SAndreas Gohr 3817caad012SAndreas Gohr $tests = [ 3827caad012SAndreas Gohr // Running behind an SSL proxy, HTTP between server and proxy 3837caad012SAndreas Gohr // Proxy (REMOTE_ADDR) is matched by trustedproxies config 3847caad012SAndreas Gohr // HTTPS not set, HTTP_X_FORWARDED_PROTO set to https 3857caad012SAndreas Gohr [$default, '127.0.0.1', '', 'https', true], 3867caad012SAndreas Gohr 3877caad012SAndreas Gohr // Running behind an SSL proxy, HTTP between server and proxy 3887caad012SAndreas Gohr // Proxy (REMOTE_ADDR) is not matched by trustedproxies config 3897caad012SAndreas Gohr // HTTPS not set, HTTP_X_FORWARDED_PROTO set to https 3907caad012SAndreas Gohr [[], '8.8.8.8', '', 'https', false], 3917caad012SAndreas Gohr 3927caad012SAndreas Gohr // Running behind a plain HTTP proxy, HTTP between server and proxy 3937caad012SAndreas Gohr // HTTPS not set, HTTP_X_FORWARDED_PROTO set to http 3947caad012SAndreas Gohr [$default, '127.0.0.1', '', 'http', false], 3957caad012SAndreas Gohr 3967caad012SAndreas Gohr // Running behind an SSL proxy, HTTP between server and proxy 3977caad012SAndreas Gohr // HTTPS set to off, HTTP_X_FORWARDED_PROTO set to https 3987caad012SAndreas Gohr [$default, '127.0.0.1', 'off', 'https', true], 3997caad012SAndreas Gohr 4007caad012SAndreas Gohr // Not running behind a proxy, HTTPS server 4017caad012SAndreas Gohr // HTTPS set to on, HTTP_X_FORWARDED_PROTO not set 4027caad012SAndreas Gohr [[], '8.8.8.8', 'on', '', true], 4037caad012SAndreas Gohr 4047caad012SAndreas Gohr // Not running behind a proxy, plain HTTP server 4057caad012SAndreas Gohr // HTTPS not set, HTTP_X_FORWARDED_PROTO not set 4067caad012SAndreas Gohr [[], '8.8.8.8', '', '', false], 4077caad012SAndreas Gohr 4087caad012SAndreas Gohr // Not running behind a proxy, plain HTTP server 4097caad012SAndreas Gohr // HTTPS set to off, HTTP_X_FORWARDED_PROTO not set 4107caad012SAndreas Gohr [[], '8.8.8.8', 'off', '', false], 4117caad012SAndreas Gohr 4127caad012SAndreas Gohr // Running behind an SSL proxy, SSL between proxy and HTTP server 4137caad012SAndreas Gohr // HTTPS set to on, HTTP_X_FORWARDED_PROTO set to https 4147caad012SAndreas Gohr [$default, '127.0.0.1', 'on', 'https', true], 4157caad012SAndreas Gohr ]; 4167caad012SAndreas Gohr 4177caad012SAndreas Gohr return $tests; 4187caad012SAndreas Gohr } 4197caad012SAndreas Gohr 4207caad012SAndreas Gohr /** 4217caad012SAndreas Gohr * Test isSsl(). 4227caad012SAndreas Gohr * 4237caad012SAndreas Gohr * @dataProvider is_ssl_provider 4247caad012SAndreas Gohr * 4257caad012SAndreas Gohr * @param string|string[] $config The trustedproxies config value. 4267caad012SAndreas Gohr * @param string $remoteAddr The REMOTE_ADDR value. 4277caad012SAndreas Gohr * @param string $https The HTTPS value. 4287caad012SAndreas Gohr * @param string $forwardedProto The HTTP_X_FORWARDED_PROTO value. 4297caad012SAndreas Gohr * @param bool $expected The expected result from isSsl(). 4307caad012SAndreas Gohr * 4317caad012SAndreas Gohr * @return void 4327caad012SAndreas Gohr */ 4337caad012SAndreas Gohr public function test_is_ssl($config, string $remoteAddr, string $https, string $forwardedProto, bool $expected): void 4347caad012SAndreas Gohr { 4357caad012SAndreas Gohr /* @var Input $INPUT */ 4367caad012SAndreas Gohr global $INPUT, $conf; 4377caad012SAndreas Gohr 4387caad012SAndreas Gohr $conf['trustedproxies'] = $config; 4397caad012SAndreas Gohr $INPUT->server->set('REMOTE_ADDR', $remoteAddr); 4407caad012SAndreas Gohr $INPUT->server->set('HTTPS', $https); 4417caad012SAndreas Gohr $INPUT->server->set('HTTP_X_FORWARDED_PROTO', $forwardedProto); 4427caad012SAndreas Gohr 4437caad012SAndreas Gohr $result = Ip::isSsl(); 4447caad012SAndreas Gohr 4457caad012SAndreas Gohr $this->assertSame($expected, $result); 4467caad012SAndreas Gohr } 4477caad012SAndreas Gohr 4487caad012SAndreas Gohr /** 4497caad012SAndreas Gohr * Data provider for test_host_name(). 4507caad012SAndreas Gohr * 4517caad012SAndreas Gohr * @return mixed[][] Returns an array of test cases. 4527caad012SAndreas Gohr */ 4537caad012SAndreas Gohr public function host_name_provider(): array 4547caad012SAndreas Gohr { 4557caad012SAndreas Gohr // The new default configuration value. 4567caad012SAndreas Gohr $default = ['::1', 'fe80::/10', '127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']; 4577caad012SAndreas Gohr 4587caad012SAndreas Gohr $tests = [ 4597caad012SAndreas Gohr // X-Forwarded-Host with trusted proxy 4607caad012SAndreas Gohr [$default, '127.0.0.1', 'proxy.example.com', 'www.example.com', 'server.local', 'proxy.example.com'], 4617caad012SAndreas Gohr 4627caad012SAndreas Gohr // X-Forwarded-Host with untrusted proxy (should fall back to HTTP_HOST) 4637caad012SAndreas Gohr [[], '8.8.8.8', 'proxy.example.com', 'www.example.com', 'server.local', 'www.example.com'], 4647caad012SAndreas Gohr 4657caad012SAndreas Gohr // No X-Forwarded-Host, use HTTP_HOST 4667caad012SAndreas Gohr [$default, '127.0.0.1', '', 'www.example.com', 'server.local', 'www.example.com'], 4677caad012SAndreas Gohr 4687caad012SAndreas Gohr // No X-Forwarded-Host or HTTP_HOST, use SERVER_NAME 4697caad012SAndreas Gohr [$default, '127.0.0.1', '', '', 'server.local', 'server.local'], 4707caad012SAndreas Gohr 4717caad012SAndreas Gohr // No headers set, should fall back to system hostname 4727caad012SAndreas Gohr [$default, '127.0.0.1', '', '', '', php_uname('n')], 4737caad012SAndreas Gohr ]; 4747caad012SAndreas Gohr 4757caad012SAndreas Gohr return $tests; 4767caad012SAndreas Gohr } 4777caad012SAndreas Gohr 4787caad012SAndreas Gohr /** 4797caad012SAndreas Gohr * Test hostName(). 4807caad012SAndreas Gohr * 4817caad012SAndreas Gohr * @dataProvider host_name_provider 4827caad012SAndreas Gohr * 4837caad012SAndreas Gohr * @param string|string[] $config The trustedproxies config value. 4847caad012SAndreas Gohr * @param string $remoteAddr The REMOTE_ADDR value. 4857caad012SAndreas Gohr * @param string $forwardedHost The HTTP_X_FORWARDED_HOST value. 4867caad012SAndreas Gohr * @param string $httpHost The HTTP_HOST value. 4877caad012SAndreas Gohr * @param string $serverName The SERVER_NAME value. 4887caad012SAndreas Gohr * @param string $expected The expected result from hostName(). 4897caad012SAndreas Gohr * 4907caad012SAndreas Gohr * @return void 4917caad012SAndreas Gohr */ 4927caad012SAndreas Gohr public function test_host_name($config, string $remoteAddr, string $forwardedHost, string $httpHost, string $serverName, string $expected): void 4937caad012SAndreas Gohr { 4947caad012SAndreas Gohr /* @var Input $INPUT */ 4957caad012SAndreas Gohr global $INPUT, $conf; 4967caad012SAndreas Gohr 4977caad012SAndreas Gohr $conf['trustedproxies'] = $config; 4987caad012SAndreas Gohr $INPUT->server->set('REMOTE_ADDR', $remoteAddr); 4997caad012SAndreas Gohr $INPUT->server->set('HTTP_X_FORWARDED_HOST', $forwardedHost); 5007caad012SAndreas Gohr $INPUT->server->set('HTTP_HOST', $httpHost); 5017caad012SAndreas Gohr $INPUT->server->set('SERVER_NAME', $serverName); 5027caad012SAndreas Gohr 5037caad012SAndreas Gohr $result = Ip::hostName(); 5047caad012SAndreas Gohr 5057caad012SAndreas Gohr $this->assertSame($expected, $result); 5067caad012SAndreas Gohr } 5072b760c9fSAlexander Lehmann 5082b760c9fSAlexander Lehmann /** 50990c2f6e3SAndreas Gohr * Test custom client IP header configuration. 5102b760c9fSAlexander Lehmann */ 5118f178b70SAlexander Lehmann public function client_ip_provider(): array 5122b760c9fSAlexander Lehmann { 5138f178b70SAlexander Lehmann return [ 514fe6048ccSAlexander Lehmann // client_ip_header disabled, X-Real-IP present -> use REMOTE_ADDR 515fe6048ccSAlexander Lehmann [null, ['HTTP_X_REAL_IP' => '5.6.7.8', 'REMOTE_ADDR' => '1.2.3.4'], '1.2.3.4'], 5162b760c9fSAlexander Lehmann 51790c2f6e3SAndreas Gohr // client_ip_header set to X_REAL_IP, X-Real-IP present -> use X-Real-IP 518fe6048ccSAlexander Lehmann ['X_REAL_IP', ['HTTP_X_REAL_IP' => '5.6.7.8', 'REMOTE_ADDR' => '1.2.3.4'], '5.6.7.8'], 5192b760c9fSAlexander Lehmann 5208f178b70SAlexander Lehmann // custom client_ip_header set to CF_CONNECTING_IP -> use CF header 521fe6048ccSAlexander Lehmann ['CF_CONNECTING_IP', ['HTTP_CF_CONNECTING_IP' => '5.6.7.8', 'REMOTE_ADDR' => '1.2.3.4'], '5.6.7.8'], 5222b760c9fSAlexander Lehmann 5238f178b70SAlexander Lehmann // client_ip_header set to X_REAL_IP but only CF header present -> fallback to REMOTE_ADDR 524fe6048ccSAlexander Lehmann ['X_REAL_IP', ['HTTP_CF_CONNECTING_IP' => '5.6.7.8', 'REMOTE_ADDR' => '1.2.3.4'], '1.2.3.4'], 5258f178b70SAlexander Lehmann ]; 5262b760c9fSAlexander Lehmann } 5272b760c9fSAlexander Lehmann 5288f178b70SAlexander Lehmann /** 5298f178b70SAlexander Lehmann * @dataProvider client_ip_provider 5308f178b70SAlexander Lehmann */ 531fe6048ccSAlexander Lehmann public function test_client_ip($client_ip_header, array $server, string $expected): void 5322b760c9fSAlexander Lehmann { 5332b760c9fSAlexander Lehmann /* @var Input $INPUT */ 5342b760c9fSAlexander Lehmann global $INPUT, $conf; 5352b760c9fSAlexander Lehmann 5368f178b70SAlexander Lehmann if ($client_ip_header !== null) { 5378f178b70SAlexander Lehmann $conf['client_ip_header'] = $client_ip_header; 5388f178b70SAlexander Lehmann } else { 5398f178b70SAlexander Lehmann unset($conf['client_ip_header']); 5402b760c9fSAlexander Lehmann } 5412b760c9fSAlexander Lehmann 5428f178b70SAlexander Lehmann // Set provided header variables 5438f178b70SAlexander Lehmann foreach ($server as $key => $value) { 5448f178b70SAlexander Lehmann $INPUT->server->set($key, $value); 5452b760c9fSAlexander Lehmann } 5462b760c9fSAlexander Lehmann 54790c2f6e3SAndreas Gohr $result = Ip::clientIp(); 5482b760c9fSAlexander Lehmann 5498f178b70SAlexander Lehmann $this->assertSame($expected, $result); 5502b760c9fSAlexander Lehmann } 5517caad012SAndreas Gohr} 552