Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.8] bpo-36384: Leading zeros in IPv4 addresses are no longer tolerated (GH-25099) #27801

Merged
merged 4 commits into from
Aug 17, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
bpo-36384: Leading zeros in IPv4 addresses are no longer tolerated (G…
…H-25099)

Reverts commit e653d4d and makes
parsing even more strict. Like socket.inet_pton() any leading zero
is now treated as invalid input.

Signed-off-by: Christian Heimes <christian@python.org>

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
  • Loading branch information
achraf-mer and ambv committed Aug 17, 2021
commit 2d462470259891eb99425e479ca6b5e6ab8ad9b3
19 changes: 17 additions & 2 deletions Doc/library/ipaddress.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ write code that handles both IP versions correctly. Address objects are
1. A string in decimal-dot notation, consisting of four decimal integers in
the inclusive range 0--255, separated by dots (e.g. ``192.168.0.1``). Each
integer represents an octet (byte) in the address. Leading zeroes are
tolerated only for values less than 8 (as there is no ambiguity
between the decimal and octal interpretations of such strings).
not tolerated to prevent confusion with octal notation.
2. An integer that fits into 32 bits.
3. An integer packed into a :class:`bytes` object of length 4 (most
significant octet first).
Expand All @@ -117,6 +116,22 @@ write code that handles both IP versions correctly. Address objects are
>>> ipaddress.IPv4Address(b'\xC0\xA8\x00\x01')
IPv4Address('192.168.0.1')

.. versionchanged:: 3.8

Leading zeros are tolerated, even in ambiguous cases that look like
octal notation.

.. versionchanged:: 3.10

Leading zeros are no longer tolerated and are treated as an error.
IPv4 address strings are now parsed as strict as glibc
:func:`~socket.inet_pton`.

.. versionchanged:: 3.9.5

The above change was also included in Python 3.9 starting with
version 3.9.5.

.. attribute:: version

The appropriate version number: ``4`` for IPv4, ``6`` for IPv6.
Expand Down
5 changes: 5 additions & 0 deletions Lib/ipaddress.py
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,11 @@ def _parse_octet(cls, octet_str):
if len(octet_str) > 3:
msg = "At most 3 characters permitted in %r"
raise ValueError(msg % octet_str)
# Handle leading zeros as strict as glibc's inet_pton()
# See security bug bpo-36384
if octet_str != '0' and octet_str[0] == '0':
msg = "Leading zeros are not permitted in %r"
raise ValueError(msg % octet_str)
# Convert to integer (we know digits are legal)
octet_int = int(octet_str, 10)
if octet_int > 255:
Expand Down
21 changes: 17 additions & 4 deletions Lib/test/test_ipaddress.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,23 @@ def pickle_test(self, addr):
class CommonTestMixin_v4(CommonTestMixin):

def test_leading_zeros(self):
self.assertInstancesEqual("000.000.000.000", "0.0.0.0")
self.assertInstancesEqual("192.168.000.001", "192.168.0.1")
self.assertInstancesEqual("016.016.016.016", "16.16.16.16")
self.assertInstancesEqual("001.000.008.016", "1.0.8.16")
# bpo-36384: no leading zeros to avoid ambiguity with octal notation
msg = "Leading zeros are not permitted in '\d+'"
addresses = [
"000.000.000.000",
"192.168.000.001",
"016.016.016.016",
"192.168.000.001",
"001.000.008.016",
"01.2.3.40",
"1.02.3.40",
"1.2.03.40",
"1.2.3.040",
]
for address in addresses:
with self.subTest(address=address):
with self.assertAddressError(msg):
self.factory(address)

def test_int(self):
self.assertInstancesEqual(0, "0.0.0.0")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
:mod:`ipaddress` module no longer accepts any leading zeros in IPv4 address
strings. Leading zeros are ambiguous and interpreted as octal notation by
some libraries. For example the legacy function :func:`socket.inet_aton`
treats leading zeros as octal notatation. glibc implementation of modern
:func:`~socket.inet_pton` does not accept any leading zeros. For a while
the :mod:`ipaddress` module used to accept ambiguous leading zeros.