diff --git a/src/ClientIp.php b/src/ClientIp.php index 9dff01c..a4e4e91 100644 --- a/src/ClientIp.php +++ b/src/ClientIp.php @@ -108,15 +108,31 @@ private function isInProxiedIps(string $ip): bool private static function isInCIDR(string $ip, string $cidr): bool { $tokens = explode('/', $cidr); - if (count($tokens) !== 2 || !self::isValid($ip) || !self::isValid($tokens[0]) || !is_numeric($tokens[1])) { + if (count($tokens) !== 2) { return false; } + if (!self::isValid($ip) && !self::isValid($tokens[0])) { + return false; + } + + if (!is_numeric($tokens[1]) || $tokens[1] < 0 || $tokens[1] > 32) { + return false; + } + + if (!ip2long($ip)) { + return false; + } + + if (!ip2long($tokens[0])) { + return false; + } + + $ip_long = ip2long($ip); $cidr_base = ip2long($tokens[0]); - $ip_long = ip2long($ip); - $mask = (0xffffffff << intval($tokens[1])) & 0xffffffff; + $mask = (int) $tokens[1]; - return ($cidr_base & $mask) === ($ip_long & $mask); + return 0 === substr_compare(sprintf('%032b', $ip_long), sprintf('%032b', $cidr_base), 0, $mask); } /** diff --git a/tests/ClientIpTest.php b/tests/ClientIpTest.php index 84076e1..d8cdf82 100644 --- a/tests/ClientIpTest.php +++ b/tests/ClientIpTest.php @@ -179,6 +179,15 @@ function ($request) { ], $request); $this->assertEquals('1.1.1.1', (string) $response->getBody()); + + $response = Dispatcher::run([ + (new ClientIp())->proxy(['1.1.1.1', '2.0.0.0/8']), + function ($request) { + echo $request->getAttribute('client-ip'); + }, + ], $request); + + $this->assertEquals('3.3.3.3', (string) $response->getBody()); } public function testNoRemoteAddr(): void