]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-87799: Improve the textual representation of IPv4-mapped IPv6 addresses...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 3 Jun 2025 13:43:36 +0000 (15:43 +0200)
committerGitHub <noreply@github.com>
Tue, 3 Jun 2025 13:43:36 +0000 (15:43 +0200)
Represent IPv4-mapped IPv6 address as x:x:x:x:x:x:d.d.d.d,
where the 'x's are the hexadecimal values
of the six high-order 16-bit pieces of the address,
and the 'd's are the decimal values
of the four low-order 8-bit pieces of the address
(standard IPv4 representation).

(cherry picked from commit f22bf8e3cf899896cf587099d29290cb43aa9724)

Co-authored-by: opavliuk <40970635+opavlyuk@users.noreply.github.com>
Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
Lib/ipaddress.py
Lib/test/test_ipaddress.py
Misc/NEWS.d/next/Library/2021-10-31-16-06-28.bpo-43633.vflwXv.rst [new file with mode: 0644]

index 6d0a103f2680390c93b61d508ad3e86ac4c1ed3c..f8c9463430410bcf7d5eafcca695a2123f8eb29b 100644 (file)
@@ -1957,8 +1957,40 @@ class IPv6Address(_BaseV6, _BaseAddress):
 
         self._ip = self._ip_int_from_string(addr_str)
 
+    def _explode_shorthand_ip_string(self):
+        ipv4_mapped = self.ipv4_mapped
+        if ipv4_mapped is None:
+            long_form = super()._explode_shorthand_ip_string()
+        else:
+            prefix_len = 30
+            raw_exploded_str = super()._explode_shorthand_ip_string()
+            long_form = "%s%s" % (raw_exploded_str[:prefix_len], str(ipv4_mapped))
+        return long_form
+
+    def _ipv4_mapped_ipv6_to_str(self):
+        """Return convenient text representation of IPv4-mapped IPv6 address
+
+        See RFC 4291 2.5.5.2, 2.2 p.3 for details.
+
+        Returns:
+            A string, 'x:x:x:x:x:x:d.d.d.d', where the 'x's are the hexadecimal values of
+            the six high-order 16-bit pieces of the address, and the 'd's are
+            the decimal values of the four low-order 8-bit pieces of the
+            address (standard IPv4 representation) as defined in RFC 4291 2.2 p.3.
+
+        """
+        ipv4_mapped = self.ipv4_mapped
+        if ipv4_mapped is None:
+            raise AddressValueError("Can not apply to non-IPv4-mapped IPv6 address %s" % str(self))
+        high_order_bits = self._ip >> 32
+        return "%s:%s" % (self._string_from_ip_int(high_order_bits), str(ipv4_mapped))
+
     def __str__(self):
-        ip_str = super().__str__()
+        ipv4_mapped = self.ipv4_mapped
+        if ipv4_mapped is None:
+            ip_str = super().__str__()
+        else:
+            ip_str = self._ipv4_mapped_ipv6_to_str()
         return ip_str + '%' + self._scope_id if self._scope_id else ip_str
 
     def __hash__(self):
index aea47d06bcb7c6f03b103129e55c7a34fbdc6a5d..398880ae0fad550e885d2423c58302371e333586 100644 (file)
@@ -1328,6 +1328,17 @@ class IpaddrUnitTest(unittest.TestCase):
         self.assertEqual(str(self.ipv6_scoped_interface.ip),
                          '2001:658:22a:cafe:200::1')
 
+    def testIPv6IPv4MappedStringRepresentation(self):
+        long_prefix = '0000:0000:0000:0000:0000:ffff:'
+        short_prefix = '::ffff:'
+        ipv4 = '1.2.3.4'
+        ipv6_ipv4_str = short_prefix + ipv4
+        ipv6_ipv4_addr = ipaddress.IPv6Address(ipv6_ipv4_str)
+        ipv6_ipv4_iface = ipaddress.IPv6Interface(ipv6_ipv4_str)
+        self.assertEqual(str(ipv6_ipv4_addr), ipv6_ipv4_str)
+        self.assertEqual(ipv6_ipv4_addr.exploded, long_prefix + ipv4)
+        self.assertEqual(str(ipv6_ipv4_iface.ip), ipv6_ipv4_str)
+
     def testGetScopeId(self):
         self.assertEqual(self.ipv6_address.scope_id,
                          None)
diff --git a/Misc/NEWS.d/next/Library/2021-10-31-16-06-28.bpo-43633.vflwXv.rst b/Misc/NEWS.d/next/Library/2021-10-31-16-06-28.bpo-43633.vflwXv.rst
new file mode 100644 (file)
index 0000000..025de1e
--- /dev/null
@@ -0,0 +1 @@
+Improve the textual representation of IPv4-mapped IPv6 addresses (:rfc:`4291` Sections 2.2, 2.5.5.2) in :mod:`ipaddress`. Patch by Oleksandr Pavliuk.\r