Skip to content

Commit c2885f9

Browse files
sethmlarsonhugovkserhiy-storchakagpshead
authored andcommitted
pythongh-128840: Limit the number of parts in IPv6 address parsing (pythonGH-128841)
pythonGH-128840: Limit the number of parts in IPv6 address parsing Limit length of IP address string to 39 --------- (cherry picked from commit 47f1161) Co-authored-by: Seth Michael Larson <[email protected]> Co-authored-by: Hugo van Kemenade <[email protected]> Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: Gregory P. Smith <[email protected]>
1 parent 38a3824 commit c2885f9

File tree

3 files changed

+22
-2
lines changed

3 files changed

+22
-2
lines changed

Lib/ipaddress.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,8 +1660,16 @@ def _ip_int_from_string(cls, ip_str):
16601660
"""
16611661
if not ip_str:
16621662
raise AddressValueError('Address cannot be empty')
1663+
if len(ip_str) > 39:
1664+
msg = ("At most 39 characters expected in "
1665+
f"{ip_str[:14]!r}({len(ip_str)-28} chars elided){ip_str[-14:]!r}")
1666+
raise AddressValueError(msg)
16631667

1664-
parts = ip_str.split(':')
1668+
# We want to allow more parts than the max to be 'split'
1669+
# to preserve the correct error message when there are
1670+
# too many parts combined with '::'
1671+
_max_parts = cls._HEXTET_COUNT + 1
1672+
parts = ip_str.split(':', maxsplit=_max_parts)
16651673

16661674
# An IPv6 address needs at least 2 colons (3 parts).
16671675
_min_parts = 3
@@ -1681,7 +1689,6 @@ def _ip_int_from_string(cls, ip_str):
16811689
# An IPv6 address can't have more than 8 colons (9 parts).
16821690
# The extra colon comes from using the "::" notation for a single
16831691
# leading or trailing zero part.
1684-
_max_parts = cls._HEXTET_COUNT + 1
16851692
if len(parts) > _max_parts:
16861693
msg = "At most %d colons permitted in %r" % (_max_parts-1, ip_str)
16871694
raise AddressValueError(msg)

Lib/test/test_ipaddress.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,17 @@ def assertBadSplit(addr):
397397
# A trailing IPv4 address is two parts
398398
assertBadSplit("10:9:8:7:6:5:4:3:42.42.42.42%scope")
399399

400+
def test_bad_address_split_v6_too_long(self):
401+
def assertBadSplit(addr):
402+
msg = r"At most 39 characters expected in %s"
403+
with self.assertAddressError(msg, repr(re.escape(addr[:14]))):
404+
ipaddress.IPv6Address(addr)
405+
406+
# Long IPv6 address
407+
long_addr = ("0:" * 10000) + "0"
408+
assertBadSplit(long_addr)
409+
assertBadSplit(long_addr + "%zoneid")
410+
400411
def test_bad_address_split_v6_too_many_parts(self):
401412
def assertBadSplit(addr):
402413
msg = "Exactly 8 parts expected without '::' in %r"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Short-circuit the processing of long IPv6 addresses early in :mod:`ipaddress` to prevent excessive
2+
memory consumption and a minor denial-of-service.

0 commit comments

Comments
 (0)