diff options
author | Vincent Petry <vincent@nextcloud.com> | 2021-11-22 15:53:41 +0100 |
---|---|---|
committer | backportbot[bot] <backportbot[bot]@users.noreply.github.com> | 2021-11-23 10:28:20 +0000 |
commit | d9a5f2867e2e6b08895ab8d696c46e09479b39bd (patch) | |
tree | 348555b2ba9bb5db764882fed7925dfc424c33e8 | |
parent | 87af149292d3b377845664bf170b923042b53295 (diff) | |
download | nextcloud-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.php | 44 | ||||
-rw-r--r-- | tests/lib/Security/Normalizer/IpAddressTest.php | 10 |
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', |