]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.10] gh-123409: fix `IPv6Address.reverse_pointer` for IPv4-mapped addresses (GH...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 3 Jun 2025 14:01:08 +0000 (16:01 +0200)
committerGitHub <noreply@github.com>
Tue, 3 Jun 2025 14:01:08 +0000 (16:01 +0200)
Fix functionality that was broken with better textual representation for IPv4-mapped addresses (gh-87799)
(cherry picked from commit 77a2fb4bf1a1b160d6ce105508288fc77f636943)

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Lib/ipaddress.py
Lib/test/test_ipaddress.py
Misc/NEWS.d/next/Library/2024-08-28-13-03-36.gh-issue-123409.lW0YF-.rst [new file with mode: 0644]

index 28ff61ec02854cc9bfe203ff0b9af3dbd94d1230..4a5d5b0e4ca7f33b40340ff25c0e00d42d2a9984 100644 (file)
@@ -1952,12 +1952,21 @@ class IPv6Address(_BaseV6, _BaseAddress):
     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
+            return super()._explode_shorthand_ip_string()
+        prefix_len = 30
+        raw_exploded_str = super()._explode_shorthand_ip_string()
+        return f"{raw_exploded_str[:prefix_len]}{ipv4_mapped!s}"
+
+    def _reverse_pointer(self):
+        ipv4_mapped = self.ipv4_mapped
+        if ipv4_mapped is None:
+            return super()._reverse_pointer()
+        prefix_len = 30
+        raw_exploded_str = super()._explode_shorthand_ip_string()[:prefix_len]
+        # ipv4 encoded using hexadecimal nibbles instead of decimals
+        ipv4_int = ipv4_mapped._ip
+        reverse_chars = f"{raw_exploded_str}{ipv4_int:008x}"[::-1].replace(':', '')
+        return '.'.join(reverse_chars) + '.ip6.arpa'
 
     def _ipv4_mapped_ipv6_to_str(self):
         """Return convenient text representation of IPv4-mapped IPv6 address
index b8b2e76a4a021a3aca01be31e4aedf2cfd2a97e3..21fdb1f709f86d24581b46359a9f0e37a57936e8 100644 (file)
@@ -2590,12 +2590,42 @@ class IpaddrUnitTest(unittest.TestCase):
         self.assertEqual('192.168.178.1', addr4.exploded)
 
     def testReversePointer(self):
-        addr1 = ipaddress.IPv4Address('127.0.0.1')
-        addr2 = ipaddress.IPv6Address('2001:db8::1')
-        self.assertEqual('1.0.0.127.in-addr.arpa', addr1.reverse_pointer)
-        self.assertEqual('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.' +
-                         'b.d.0.1.0.0.2.ip6.arpa',
-                         addr2.reverse_pointer)
+        for addr_v4, expected in [
+            ('127.0.0.1', '1.0.0.127.in-addr.arpa'),
+            # test vector: https://www.rfc-editor.org/rfc/rfc1035, §3.5
+            ('10.2.0.52', '52.0.2.10.in-addr.arpa'),
+        ]:
+            with self.subTest('ipv4_reverse_pointer', addr=addr_v4):
+                addr = ipaddress.IPv4Address(addr_v4)
+                self.assertEqual(addr.reverse_pointer, expected)
+
+        for addr_v6, expected in [
+            (
+                '2001:db8::1', (
+                    '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.'
+                    '0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.'
+                    'ip6.arpa'
+                )
+            ),
+            (
+                '::FFFF:192.168.1.35', (
+                    '3.2.1.0.8.a.0.c.f.f.f.f.0.0.0.0.'
+                    '0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.'
+                    'ip6.arpa'
+                )
+            ),
+            # test vector: https://www.rfc-editor.org/rfc/rfc3596, §2.5
+            (
+                '4321:0:1:2:3:4:567:89ab', (
+                    'b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.'
+                    '2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.'
+                    'ip6.arpa'
+                )
+             )
+        ]:
+            with self.subTest('ipv6_reverse_pointer', addr=addr_v6):
+                addr = ipaddress.IPv6Address(addr_v6)
+                self.assertEqual(addr.reverse_pointer, expected)
 
     def testIntRepresentation(self):
         self.assertEqual(16909060, int(self.ipv4_address))
diff --git a/Misc/NEWS.d/next/Library/2024-08-28-13-03-36.gh-issue-123409.lW0YF-.rst b/Misc/NEWS.d/next/Library/2024-08-28-13-03-36.gh-issue-123409.lW0YF-.rst
new file mode 100644 (file)
index 0000000..7c6aab6
--- /dev/null
@@ -0,0 +1,2 @@
+Fix :attr:`ipaddress.IPv6Address.reverse_pointer` output according to
+:rfc:`RFC 3596, §2.5 <3596#section-2.5>`.  Patch by Bénédikt Tran.