Skip to content

Commit f04035c

Browse files
committed
Simplify IP address normalizer with IP masks
Remove dead code Signed-off-by: Benjamin Gaussorgues <benjamin.gaussorgues@nextcloud.com>
1 parent 9285fe0 commit f04035c

1 file changed

Lines changed: 15 additions & 54 deletions

File tree

lib/private/Security/Normalizer/IpAddress.php

Lines changed: 15 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -38,48 +38,29 @@
3838
*/
3939
class IpAddress {
4040
/**
41-
* @param string $ip IP to normalized
41+
* @param string $ip IP to normalize
4242
*/
4343
public function __construct(
4444
private string $ip,
4545
) {
4646
}
4747

4848
/**
49-
* Return the given subnet for an IPv4 address and mask bits
49+
* Return the given subnet for an IPv6 address (64 first bits)
5050
*/
51-
private function getIPv4Subnet(string $ip, int $maskBits = 32): string {
52-
$binary = \inet_pton($ip);
53-
for ($i = 32; $i > $maskBits; $i -= 8) {
54-
$j = \intdiv($i, 8) - 1;
55-
$k = \min(8, $i - $maskBits);
56-
$mask = (0xff - ((2 ** $k) - 1));
57-
$int = \unpack('C', $binary[$j]);
58-
$binary[$j] = \pack('C', $int[1] & $mask);
59-
}
60-
return \inet_ntop($binary).'/'.$maskBits;
61-
}
62-
63-
/**
64-
* Return the given subnet for an IPv6 address and mask bits
65-
*/
66-
private function getIPv6Subnet(string $ip, int $maskBits = 48): string {
51+
private function getIPv6Subnet(string $ip): string {
6752
if ($ip[0] === '[' && $ip[-1] === ']') { // If IP is with brackets, for example [::1]
6853
$ip = substr($ip, 1, strlen($ip) - 2);
6954
}
7055
$pos = strpos($ip, '%'); // if there is an explicit interface added to the IP, e.g. fe80::ae2d:d1e7:fe1e:9a8d%enp2s0
7156
if ($pos !== false) {
7257
$ip = substr($ip, 0, $pos - 1);
7358
}
59+
7460
$binary = \inet_pton($ip);
75-
for ($i = 128; $i > $maskBits; $i -= 8) {
76-
$j = \intdiv($i, 8) - 1;
77-
$k = \min(8, $i - $maskBits);
78-
$mask = (0xff - ((2 ** $k) - 1));
79-
$int = \unpack('C', $binary[$j]);
80-
$binary[$j] = \pack('C', $int[1] & $mask);
81-
}
82-
return \inet_ntop($binary).'/'.$maskBits;
61+
$mask = inet_pton('FFFF:FFFF:FFFF:FFFF::');
62+
63+
return inet_ntop($binary & $mask).'/64';
8364
}
8465

8566
/**
@@ -93,50 +74,30 @@ private function getEmbeddedIpv4(string $ipv6): ?string {
9374
if (!$binary) {
9475
return null;
9576
}
96-
for ($i = 0; $i <= 9; $i++) {
97-
if (unpack('C', $binary[$i])[1] !== 0) {
98-
return null;
99-
}
100-
}
10177

102-
for ($i = 10; $i <= 11; $i++) {
103-
if (unpack('C', $binary[$i])[1] !== 255) {
104-
return null;
105-
}
106-
}
107-
108-
$binary4 = '';
109-
for ($i = 12; $i < 16; $i++) {
110-
$binary4 .= $binary[$i];
78+
$mask = inet_pton('::FFFF:FFFF');
79+
if (($binary & ~$mask) !== inet_pton('::FFFF:0.0.0.0')) {
80+
return null;
11181
}
11282

113-
return inet_ntop($binary4);
83+
return inet_ntop(substr($binary, -4));
11484
}
11585

11686

11787
/**
11888
* Gets either the /32 (IPv4) or the /64 (IPv6) subnet of an IP address
11989
*/
12090
public function getSubnet(): string {
121-
if (\preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->ip)) {
122-
return $this->getIPv4Subnet(
123-
$this->ip,
124-
32
125-
);
91+
if (filter_var($this->ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
92+
return $this->ip.'/32';
12693
}
12794

12895
$ipv4 = $this->getEmbeddedIpv4($this->ip);
12996
if ($ipv4 !== null) {
130-
return $this->getIPv4Subnet(
131-
$ipv4,
132-
32
133-
);
97+
return $ipv4.'/32';
13498
}
13599

136-
return $this->getIPv6Subnet(
137-
$this->ip,
138-
64
139-
);
100+
return $this->getIPv6Subnet($this->ip);
140101
}
141102

142103
/**

0 commit comments

Comments
 (0)