Skip to content

Commit da37555

Browse files
miss-islingtonsethmlarsonhugovkserhiy-storchakagpshead
authored
[3.11] gh-128840: Limit the number of parts in IPv6 address parsing (GH-128841) (GH-134613)
Limit length of IP address string to 39 (cherry picked from commit 47f1161) Co-authored-by: Seth Michael Larson <seth@python.org> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Gregory P. Smith <greg@krypto.org>
1 parent f38f9cf commit da37555

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
@@ -1664,8 +1664,16 @@ def _ip_int_from_string(cls, ip_str):
16641664
"""
16651665
if not ip_str:
16661666
raise AddressValueError('Address cannot be empty')
1667+
if len(ip_str) > 39:
1668+
msg = ("At most 39 characters expected in "
1669+
f"{ip_str[:14]!r}({len(ip_str)-28} chars elided){ip_str[-14:]!r}")
1670+
raise AddressValueError(msg)
16671671

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

16701678
# An IPv6 address needs at least 2 colons (3 parts).
16711679
_min_parts = 3
@@ -1685,7 +1693,6 @@ def _ip_int_from_string(cls, ip_str):
16851693
# An IPv6 address can't have more than 8 colons (9 parts).
16861694
# The extra colon comes from using the "::" notation for a single
16871695
# leading or trailing zero part.
1688-
_max_parts = cls._HEXTET_COUNT + 1
16891696
if len(parts) > _max_parts:
16901697
msg = "At most %d colons permitted in %r" % (_max_parts-1, ip_str)
16911698
raise AddressValueError(msg)

Lib/test/test_ipaddress.py

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

392+
def test_bad_address_split_v6_too_long(self):
393+
def assertBadSplit(addr):
394+
msg = r"At most 39 characters expected in %s"
395+
with self.assertAddressError(msg, repr(re.escape(addr[:14]))):
396+
ipaddress.IPv6Address(addr)
397+
398+
# Long IPv6 address
399+
long_addr = ("0:" * 10000) + "0"
400+
assertBadSplit(long_addr)
401+
assertBadSplit(long_addr + "%zoneid")
402+
392403
def test_bad_address_split_v6_too_many_parts(self):
393404
def assertBadSplit(addr):
394405
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)