https://github.com/python/cpython/commit/a0287bf574e0b76892026ae7c8d4642fdbe872ec
commit: a0287bf574e0b76892026ae7c8d4642fdbe872ec
branch: 3.13
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: gpshead <g...@krypto.org>
date: 2025-05-28T15:46:40Z
summary:

[3.13] gh-128840: Fix parsing long IPv6 addresses with embedded IPv4 address 
(GH-134836) (#134846)

gh-128840: Fix parsing long IPv6 addresses with embedded IPv4 address 
(GH-134836)
(cherry picked from commit d83576bf48d07d5e29d5d171c4e25afb048622aa)

Co-authored-by: Serhiy Storchaka <storch...@gmail.com>

files:
A Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst
M Lib/ipaddress.py
M Lib/test/test_ipaddress.py

diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 6ab6f99dad7a1b..67e45450fc1c9f 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1674,10 +1674,12 @@ def _ip_int_from_string(cls, ip_str):
         """
         if not ip_str:
             raise AddressValueError('Address cannot be empty')
-        if len(ip_str) > 39:
-            msg = ("At most 39 characters expected in "
-                   f"{ip_str[:14]!r}({len(ip_str)-28} chars 
elided){ip_str[-14:]!r}")
-            raise AddressValueError(msg)
+        if len(ip_str) > 45:
+            shorten = ip_str
+            if len(shorten) > 100:
+                shorten = f'{ip_str[:45]}({len(ip_str)-90} chars 
elided){ip_str[-45:]}'
+            raise AddressValueError(f"At most 45 characters expected in "
+                                    f"{shorten!r}")
 
         # We want to allow more parts than the max to be 'split'
         # to preserve the correct error message when there are
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index 7a27be16965d0b..e69e12495ad5c1 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -399,14 +399,16 @@ def assertBadSplit(addr):
 
     def test_bad_address_split_v6_too_long(self):
         def assertBadSplit(addr):
-            msg = r"At most 39 characters expected in %s"
-            with self.assertAddressError(msg, repr(re.escape(addr[:14]))):
+            msg = r"At most 45 characters expected in '%s"
+            with self.assertAddressError(msg, re.escape(addr[:45])):
                 ipaddress.IPv6Address(addr)
 
         # Long IPv6 address
         long_addr = ("0:" * 10000) + "0"
         assertBadSplit(long_addr)
         assertBadSplit(long_addr + "%zoneid")
+        assertBadSplit(long_addr + ":255.255.255.255")
+        assertBadSplit(long_addr + ":ffff:255.255.255.255")
 
     def test_bad_address_split_v6_too_many_parts(self):
         def assertBadSplit(addr):
@@ -2189,6 +2191,11 @@ def testIPv6AddressTooLarge(self):
         self.assertEqual(ipaddress.ip_address('FFFF::192.0.2.1'),
                           ipaddress.ip_address('FFFF::c000:201'))
 
+        
self.assertEqual(ipaddress.ip_address('0000:0000:0000:0000:0000:FFFF:192.168.255.255'),
+                          ipaddress.ip_address('::ffff:c0a8:ffff'))
+        
self.assertEqual(ipaddress.ip_address('FFFF:0000:0000:0000:0000:0000:192.168.255.255'),
+                          ipaddress.ip_address('ffff::c0a8:ffff'))
+
         self.assertEqual(ipaddress.ip_address('::FFFF:192.0.2.1%scope'),
                           ipaddress.ip_address('::FFFF:c000:201%scope'))
         self.assertEqual(ipaddress.ip_address('FFFF::192.0.2.1%scope'),
@@ -2201,6 +2208,10 @@ def testIPv6AddressTooLarge(self):
                           ipaddress.ip_address('::FFFF:c000:201%scope'))
         self.assertNotEqual(ipaddress.ip_address('FFFF::192.0.2.1'),
                           ipaddress.ip_address('FFFF::c000:201%scope'))
+        
self.assertEqual(ipaddress.ip_address('0000:0000:0000:0000:0000:FFFF:192.168.255.255%scope'),
+                          ipaddress.ip_address('::ffff:c0a8:ffff%scope'))
+        
self.assertEqual(ipaddress.ip_address('FFFF:0000:0000:0000:0000:0000:192.168.255.255%scope'),
+                          ipaddress.ip_address('ffff::c0a8:ffff%scope'))
 
     def testIPVersion(self):
         self.assertEqual(self.ipv4_address.version, 4)
@@ -2604,6 +2615,10 @@ def testCompressIPv6Address(self):
             '::7:6:5:4:3:2:0': '0:7:6:5:4:3:2:0/128',
             '7:6:5:4:3:2:1::': '7:6:5:4:3:2:1:0/128',
             '0:6:5:4:3:2:1::': '0:6:5:4:3:2:1:0/128',
+            '0000:0000:0000:0000:0000:0000:255.255.255.255': '::ffff:ffff/128',
+            '0000:0000:0000:0000:0000:ffff:255.255.255.255': 
'::ffff:255.255.255.255/128',
+            'ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255':
+                'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128',
             }
         for uncompressed, compressed in list(test_addresses.items()):
             self.assertEqual(compressed, str(ipaddress.IPv6Interface(
diff --git 
a/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst 
b/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst
new file mode 100644
index 00000000000000..faff433aa4b86e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst
@@ -0,0 +1 @@
+Fix parsing long IPv6 addresses with embedded IPv4 address.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to