aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Petry <vincent@nextcloud.com>2021-11-22 15:53:41 +0100
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>2021-11-23 10:28:20 +0000
commitd9a5f2867e2e6b08895ab8d696c46e09479b39bd (patch)
tree348555b2ba9bb5db764882fed7925dfc424c33e8
parent87af149292d3b377845664bf170b923042b53295 (diff)
downloadnextcloud-server-d9a5f2867e2e6b08895ab8d696c46e09479b39bd.tar.gz
nextcloud-server-d9a5f2867e2e6b08895ab8d696c46e09479b39bd.zip
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 <vincent@nextcloud.com>
-rw-r--r--lib/private/Security/Normalizer/IpAddress.php44
-rw-r--r--tests/lib/Security/Normalizer/IpAddressTest.php10
2 files changed, 51 insertions, 3 deletions
diff --git a/lib/private/Security/Normalizer/IpAddress.php b/lib/private/Security/Normalizer/IpAddress.php
index f878c9f986b..c442391dc3e 100644
--- a/lib/private/Security/Normalizer/IpAddress.php
+++ b/lib/private/Security/Normalizer/IpAddress.php
@@ -93,6 +93,39 @@ class IpAddress {
}
/**
+ * Returns the IPv4 address embedded in an IPv6 if applicable.
+ * The detected format is "::ffff:x.x.x.x" using the binary form.
+ *
+ * @param string $ipv6 IPv6 string
+ * @return null|string embedded IPv4 string or null if none was found
+ */
+ private function getEmbeddedIpv4($ipv6) {
+ $binary = inet_pton($ipv6);
+ if (!$binary) {
+ return null;
+ }
+ for ($i = 0; $i <= 9; $i++) {
+ if (unpack('C', $binary[$i])[1] !== 0) {
+ return null;
+ }
+ }
+
+ for ($i = 10; $i <= 11; $i++) {
+ if (unpack('C', $binary[$i])[1] !== 255) {
+ return null;
+ }
+ }
+
+ $binary4 = '';
+ for ($i = 12; $i < 16; $i++) {
+ $binary4 .= $binary[$i];
+ }
+
+ return inet_ntop($binary4);
+ }
+
+
+ /**
* Gets either the /32 (IPv4) or the /64 (IPv6) subnet of an IP address
*
* @return string
@@ -103,9 +136,16 @@ class IpAddress {
$this->ip,
32
);
- } elseif (substr(strtolower($this->ip), 0, 7) === '::ffff:') {
- return '::ffff:' . $this->getIPv4Subnet(substr($this->ip, 7), 32);
}
+
+ $ipv4 = $this->getEmbeddedIpv4($this->ip);
+ if ($ipv4 !== null) {
+ return $this->getIPv4Subnet(
+ $ipv4,
+ 32
+ );
+ }
+
return $this->getIPv6Subnet(
$this->ip,
64
diff --git a/tests/lib/Security/Normalizer/IpAddressTest.php b/tests/lib/Security/Normalizer/IpAddressTest.php
index a3c839adc3b..86b03f7d209 100644
--- a/tests/lib/Security/Normalizer/IpAddressTest.php
+++ b/tests/lib/Security/Normalizer/IpAddressTest.php
@@ -37,7 +37,15 @@ class IpAddressTest extends TestCase {
],
[
'::ffff:192.168.0.123',
- '::ffff:192.168.0.123/32',
+ '192.168.0.123/32',
+ ],
+ [
+ '0:0:0:0:0:ffff:192.168.0.123',
+ '192.168.0.123/32',
+ ],
+ [
+ '0:0:0:0:0:ffff:c0a8:7b',
+ '192.168.0.123/32',
],
[
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',