bpo-36384: Leading zeros in IPv4 addresses are no longer tolerated (GH-25099)

Reverts commit e653d4d8e820a7a004ad399530af0135b45db27a 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>
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 160b16d..af7aedf 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1223,6 +1223,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:
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index 3c07008..cdd9880 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -96,10 +96,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")