From da2258f18d42c4cbab7ff31cfc7407a93f3cfbf2 Mon Sep 17 00:00:00 2001 From: zeightnoteight <6435796+zeightnoteight@users.noreply.github.com> Date: Sat, 12 Jan 2019 17:10:10 +0530 Subject: [PATCH 1/2] adding cidr range support to proxied ip addresses --- src/ClientIp.php | 36 +++++++++++++++++++++++++++++++++--- tests/ClientIpTest.php | 9 +++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/ClientIp.php b/src/ClientIp.php index effb81b..9dbf622 100644 --- a/src/ClientIp.php +++ b/src/ClientIp.php @@ -97,7 +97,7 @@ private function getIp(ServerRequestInterface $request) $localIp = $this->getLocalIp($request); - if ($this->proxyIps && !in_array($localIp, $this->proxyIps)) { + if ($this->proxyIps && !$this->isInProxiedIps($localIp)) { // Local IP address does not point at a known proxy, do not attempt // to read proxied IP address. return $localIp; @@ -113,6 +113,36 @@ private function getIp(ServerRequestInterface $request) return $localIp; } + /** + * checks if the given ip address is in the list of proxied ips provided + * + * @param string $ip + * @return bool + */ + private function isInProxiedIps(string $ip): bool + { + foreach ($this->proxyIps as $proxyIp) { + if ($ip === $proxyIp || self::isInCIDR($ip, $proxyIp)) { + return true; + } + } + return false; + } + + 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])) { + return false; + } + + $cidr_base = ip2long($tokens[0]); + $ip_long = ip2long($ip); + $mask = (0xffffffff << intval($tokens[1])) & 0xffffffff; + + return ($cidr_base & $mask) === ($ip_long & $mask); + } + /** * Returns the IP address from remote service. * @@ -180,7 +210,7 @@ private function getForwardedHeaderIp(string $header) $ip = trim(substr($directive, 4)); - if (self::isValid($ip) && !in_array($ip, $this->proxyIps)) { + if (self::isValid($ip) && !$this->isInProxiedIps($ip)) { return $ip; } } @@ -195,7 +225,7 @@ private function getForwardedHeaderIp(string $header) private function getHeaderIp(string $header) { foreach (array_reverse(array_map('trim', explode(',', $header))) as $ip) { - if (self::isValid($ip) && !in_array($ip, $this->proxyIps)) { + if (self::isValid($ip) && !$this->isInProxiedIps($ip)) { return $ip; } } diff --git a/tests/ClientIpTest.php b/tests/ClientIpTest.php index e86dad8..6643de0 100644 --- a/tests/ClientIpTest.php +++ b/tests/ClientIpTest.php @@ -145,6 +145,15 @@ function ($request) { ], $request); $this->assertEquals('3.3.3.3', (string) $response->getBody()); + + $response = Dispatcher::run([ + (new ClientIp())->proxy(['1.1.0.0/16', '2.2.2.0/8']), + function ($request) { + echo $request->getAttribute('client-ip'); + }, + ], $request); + + $this->assertEquals('3.3.3.3', (string) $response->getBody()); } public function testNoRemoteAddr() From 2ea264574f902ea7481fc869e13a2e0ecbdb2662 Mon Sep 17 00:00:00 2001 From: zeightnoteight <6435796+zeightnoteight@users.noreply.github.com> Date: Sat, 12 Jan 2019 18:24:18 +0530 Subject: [PATCH 2/2] add an extra test for non matching proxy --- tests/ClientIpTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ClientIpTest.php b/tests/ClientIpTest.php index 6643de0..e237d06 100644 --- a/tests/ClientIpTest.php +++ b/tests/ClientIpTest.php @@ -154,6 +154,15 @@ function ($request) { ], $request); $this->assertEquals('3.3.3.3', (string) $response->getBody()); + + $response = Dispatcher::run([ + (new ClientIp())->proxy(['5.5.5.0/12']), + function ($request) { + echo $request->getAttribute('client-ip'); + }, + ], $request); + + $this->assertEquals('1.1.1.1', (string) $response->getBody()); } public function testNoRemoteAddr()