Skip to content

Commit

Permalink
Merge pull request #37 from kudashevs/feature/little_improvements
Browse files Browse the repository at this point in the history
Some little improvements
  • Loading branch information
akrabat authored Jan 18, 2022
2 parents 394c0fe + 10c91d7 commit 5c4e76a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 26 deletions.
70 changes: 47 additions & 23 deletions src/IpAddress.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ class IpAddress implements MiddlewareInterface
*
* @var array
*/
protected $trustedWildcard;
protected $trustedWildcards;

/**
* List of trusted proxy IP CIDR ranges
*
* @var array
*/
protected $trustedCidr;
protected $trustedCidrs;

/**
* Name of the attribute added to the ServerRequest object
Expand Down Expand Up @@ -86,23 +86,10 @@ public function __construct(
foreach ($trustedProxies as $proxy) {
if (strpos($proxy, '*') !== false) {
// Wildcard IP address
// IPv6 is 8 parts separated by ':'
if (strpos($proxy, '.') > 0) {
$delim = '.';
$parts = 4;
} else {
$delim = ':';
$parts = 8;
}
$this->trustedWildcard[] = explode($delim, $proxy, $parts);
$this->trustedWildcards[] = $this->parseWildcard($proxy);
} elseif (strpos($proxy, '/') > 6) {
// CIDR notation
list($subnet, $bits) = explode('/', $proxy, 2);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$min = $subnet & $mask;
$max = $subnet | ~$mask;
$this->trustedCidr[] = [$min, $max];
$this->trustedCidrs[] = $this->parseCidr($proxy);
} else {
// String-match IP address
$this->trustedProxies[] = $proxy;
Expand All @@ -113,11 +100,46 @@ public function __construct(
if ($attributeName) {
$this->attributeName = $attributeName;
}

if (!empty($headersToInspect)) {
$this->headersToInspect = $headersToInspect;
}
}

/**
* @param string $ipAddress
* @return array
*/
private function parseWildcard(string $ipAddress)
{
// IPv4 has 4 parts separated by '.'
// IPv6 has 8 parts separated by ':'
if (strpos($ipAddress, '.') > 0) {
$delim = '.';
$parts = 4;
} else {
$delim = ':';
$parts = 8;
}

return explode($delim, $ipAddress, $parts);
}

/**
* @param string $ipAddress
* @return array
*/
private function parseCidr(string $ipAddress)
{
list($subnet, $bits) = explode('/', $ipAddress, 2);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
$min = $subnet & $mask;
$max = $subnet | ~$mask;

return [$min, $max];
}

/**
* {@inheritDoc}
*
Expand Down Expand Up @@ -180,7 +202,7 @@ protected function determineClientIpAddress($request)
}

// Wildcard Match
if ($this->checkProxyHeaders && $this->trustedWildcard) {
if ($this->checkProxyHeaders && $this->trustedWildcards) {
// IPv4 has 4 parts separated by '.'
// IPv6 has 8 parts separated by ':'
if (strpos($ipAddress, '.') > 0) {
Expand All @@ -190,16 +212,17 @@ protected function determineClientIpAddress($request)
$delim = ':';
$parts = 8;
}

$ipAddrParts = explode($delim, $ipAddress, $parts);
foreach ($this->trustedWildcard as $proxy) {
foreach ($this->trustedWildcards as $proxy) {
if (count($proxy) !== $parts) {
continue; // IP version does not match
}
$match = true;
foreach ($proxy as $i => $part) {
if ($part !== '*' && $part !== $ipAddrParts[$i]) {
$match = false;
break;// IP does not match, move to next proxy
break; // IP does not match, move to next proxy
}
}
if ($match) {
Expand All @@ -210,11 +233,11 @@ protected function determineClientIpAddress($request)
}

// CIDR Match
if ($this->checkProxyHeaders && $this->trustedCidr) {
if ($this->checkProxyHeaders && $this->trustedCidrs) {
// Only IPv4 is supported for CIDR matching
$ipAsLong = ip2long($ipAddress);
if ($ipAsLong) {
foreach ($this->trustedCidr as $proxy) {
foreach ($this->trustedCidrs as $proxy) {
if ($proxy[0] <= $ipAsLong && $ipAsLong <= $proxy[1]) {
$checkProxyHeaders = true;
break;
Expand All @@ -223,7 +246,7 @@ protected function determineClientIpAddress($request)
}
}

if (!$this->trustedProxies && !$this->trustedWildcard && !$this->trustedCidr) {
if (!$this->trustedProxies && !$this->trustedWildcards && !$this->trustedCidrs) {
$checkProxyHeaders = true;
}

Expand Down Expand Up @@ -279,6 +302,7 @@ protected function isValidIpAddress($ip)
if (filter_var($ip, FILTER_VALIDATE_IP, $flags) === false) {
return false;
}

return true;
}

Expand Down
4 changes: 1 addition & 3 deletions tests/IpAddressTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ public function testIpIsNullIfMissingAndProxiesAreConfigured()
$this->assertSame(null, $ipAddress);
}


public function testXForwardedForIp()
{
$middleware = new IPAddress(true, []);
Expand All @@ -163,7 +162,7 @@ public function testXForwardedForIpWithPort()
$this->assertSame('192.168.1.3', $ipAddress);
}

public function testProxyIpIsIgnored()
public function testProxyIpIsIgnoredWhenNoArgumentsProvided()
{
$middleware = new IPAddress();
$env = [
Expand Down Expand Up @@ -294,7 +293,6 @@ public function testCustomHeader()
$this->assertSame('192.168.1.3', $ipAddress);
}


public function testPSR15()
{
$middleware = new IPAddress();
Expand Down

0 comments on commit 5c4e76a

Please sign in to comment.