File gh-128840_parse-IPv6-with-emb-IPv4.patch of Package python3.39454
---
Lib/ipaddress.py | 18 ++++++
Lib/test/test_ipaddress.py | 27 ++++++++++
Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst | 1
3 files changed, 46 insertions(+)
Index: Python-3.4.10/Lib/ipaddress.py
===================================================================
--- Python-3.4.10.orig/Lib/ipaddress.py 2025-06-25 20:09:03.598854621 +0200
+++ Python-3.4.10/Lib/ipaddress.py 2025-06-25 20:09:08.743128970 +0200
@@ -1196,6 +1196,12 @@
if not ip_str:
raise AddressValueError('Address cannot be empty')
+ if len(ip_str) > 45:
+ shorten = ip_str
+ if len(shorten) > 100:
+ shorten = '{}({} chars elided){}'.format(ip_str[:45], len(ip_str)-90, ip_str[-45:])
+ raise AddressValueError("At most 45 characters expected in {!r}".format(shorten))
+
octets = ip_str.split('.')
if len(octets) != 4:
raise AddressValueError("Expected 4 octets in %r" % ip_str)
@@ -1639,6 +1645,8 @@
_HEXTET_COUNT = 8
_HEX_DIGITS = frozenset('0123456789ABCDEFabcdef')
_max_prefixlen = IPV6LENGTH
+ # The longest valid IPv6 string is 39 chars, so 45 provides buffer.
+ _MAX_STR_LEN = 45
@classmethod
def _ip_int_from_prefix(cls, prefixlen):
@@ -1757,6 +1765,16 @@
if not ip_str:
raise AddressValueError('Address cannot be empty')
+ # Add this general string length check at the beginning for consistency with IPv4
+ # and to catch extremely long invalid inputs before more complex parsing.
+ if len(ip_str) > cls._MAX_STR_LEN:
+ shorten = ip_str
+ # If the string is exceedingly long, elide characters for readability in the error message.
+ if len(shorten) > 100: # Arbitrary threshold for shortening
+ shorten = '{}({} chars elided){}'.format(ip_str[:45], len(ip_str)-90, ip_str[-45:])
+ raise AddressValueError("At most {} characters expected in ".format(cls._MAX_STR_LEN) +
+ "{!r}".format(shorten))
+
parts = ip_str.split(':')
# An IPv6 address needs at least 2 colons (3 parts).
Index: Python-3.4.10/Lib/test/test_ipaddress.py
===================================================================
--- Python-3.4.10.orig/Lib/test/test_ipaddress.py 2025-06-25 20:09:03.600605345 +0200
+++ Python-3.4.10/Lib/test/test_ipaddress.py 2025-06-25 20:09:08.743865661 +0200
@@ -313,6 +313,19 @@
# A trailing IPv4 address is two parts
assertBadSplit("10:9:8:7:6:5:4:3:42.42.42.42")
+ def test_bad_address_split_v6_too_long(self):
+ def assertBadSplit(addr):
+ msg = r"At most 45 characters expected in '.*?'"
+ with self.assertAddressError(msg):
+ 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):
msg = r"Exactly \d+ parts expected without '::' in '.*?'"
@@ -1723,6 +1736,16 @@
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('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)
self.assertEqual(self.ipv6_address.version, 6)
@@ -2004,6 +2027,10 @@
'::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:ffff:ffff/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(
Index: Python-3.4.10/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.4.10/Misc/NEWS.d/next/Library/2025-05-28-15-53-27.gh-issue-128840.Nur2pB.rst 2025-06-25 20:09:08.744349594 +0200
@@ -0,0 +1 @@
+Fix parsing long IPv6 addresses with embedded IPv4 address.