Skip to content

Commit f01ad7b

Browse files
committed
Improve normalizer detecting IPv4 inside of IPv6
The subnet for an IPv4 address inside of IPv6 is now returned in its IPv4 form. Signed-off-by: Vincent Petry <[email protected]>
1 parent 7e08a4a commit f01ad7b

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

lib/private/Security/Normalizer/IpAddress.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,39 @@ private function getIPv6Subnet(string $ip, int $maskBits = 48): string {
9292
return \inet_ntop($binary).'/'.$maskBits;
9393
}
9494

95+
/**
96+
* Returns the IPv4 address embedded in an IPv6 if applicable.
97+
* The detected format is "::ffff:x.x.x.x" using the binary form.
98+
*
99+
* @param string $ipv6 IPv6 string
100+
* @return null|string embedded IPv4 string or null if none was found
101+
*/
102+
private function getEmbeddedIpv4($ipv6) {
103+
$binary = inet_pton($ipv6);
104+
if (!$binary) {
105+
return null;
106+
}
107+
for ($i = 0; $i <= 9; $i++) {
108+
if (unpack('C', $binary[$i])[1] !== 0) {
109+
return null;
110+
}
111+
}
112+
113+
for ($i = 10; $i <= 11; $i++) {
114+
if (unpack('C', $binary[$i])[1] !== 255) {
115+
return null;
116+
}
117+
}
118+
119+
$binary4 = '';
120+
for ($i = 12; $i < 16; $i++) {
121+
$binary4 .= $binary[$i];
122+
}
123+
124+
return inet_ntop($binary4);
125+
}
126+
127+
95128
/**
96129
* Gets either the /32 (IPv4) or the /64 (IPv6) subnet of an IP address
97130
*
@@ -103,9 +136,16 @@ public function getSubnet(): string {
103136
$this->ip,
104137
32
105138
);
106-
} elseif (substr(strtolower($this->ip), 0, 7) === '::ffff:') {
107-
return '::ffff:' . $this->getIPv4Subnet(substr($this->ip, 7), 32);
108139
}
140+
141+
$ipv4 = $this->getEmbeddedIpv4($this->ip);
142+
if ($ipv4 !== null) {
143+
return $this->getIPv4Subnet(
144+
$ipv4,
145+
32
146+
);
147+
}
148+
109149
return $this->getIPv6Subnet(
110150
$this->ip,
111151
64

tests/lib/Security/Normalizer/IpAddressTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,15 @@ public function subnetDataProvider() {
4040
],
4141
[
4242
'::ffff:192.168.0.123',
43-
'::ffff:192.168.0.123/32',
43+
'192.168.0.123/32',
44+
],
45+
[
46+
'0:0:0:0:0:ffff:192.168.0.123',
47+
'192.168.0.123/32',
48+
],
49+
[
50+
'0:0:0:0:0:ffff:c0a8:7b',
51+
'192.168.0.123/32',
4452
],
4553
[
4654
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',

0 commit comments

Comments
 (0)