Replace the obsolete third-party ipaddr module with Python's standard
library ipaddress module.
Update IP address and network validation throughout Compute Engine,
Cloud DNS, and App Engine. Use ip_network(strict=False) to preserve
ipaddr.IPNetwork behavior for networks with host bits set.
Remove the Python 2-specific conditional import and enable local
subnet validation on Python 3.
--- ../lib/googlecloudsdk/command_lib/dns/util.py	2026-10-19 01:14:14.467250104 +0300
+++ ../lib/googlecloudsdk/command_lib/dns/util.py	2026-10-19 01:14:58.830443293 +0300
@@ -22,13 +22,13 @@
 from googlecloudsdk.core import properties
 from googlecloudsdk.core import resources
 
-import ipaddr
+import ipaddress
 
 
 def IsIPv4(ip: str) -> bool:
   """Returns True if ip is an IPv4."""
   try:
-    ipaddr.IPv4Address(ip)
+    ipaddress.IPv4Address(ip)
     return True
   except ValueError:
     return False
@@ -37,7 +37,7 @@
 def IsIPv6(ip: str) -> bool:
   """Returns True if ip is an IPv6."""
   try:
-    ipaddr.IPv6Address(ip)
+    ipaddress.IPv6Address(ip)
     return True
   except ValueError:
     return False
--- ../lib/googlecloudsdk/api_lib/compute/utils.py	2026-10-19 10:54:18.608095513 +0300
+++ ../lib/googlecloudsdk/api_lib/compute/utils.py	2026-10-19 10:55:01.720638722 +0300
@@ -26,7 +26,7 @@
 from googlecloudsdk.core import log
 from googlecloudsdk.core.console import console_io
 from googlecloudsdk.core.resource import resource_printer
-import ipaddr
+import ipaddress
 import six
 
 COMPUTE_ALPHA_API_VERSION = 'alpha'
@@ -341,8 +341,8 @@
 def IsValidIPV6(ip):
   """Accepts an ipv6 address in string form and returns True if valid."""
   try:
-    ipaddr.IPv6Address(ip)
-  except ipaddr.AddressValueError:
+    ipaddress.IPv6Address(ip)
+  except ipaddress.AddressValueError:
     return False
   return True
 
--- ../lib/googlecloudsdk/api_lib/dns/resource_record_sets.py	2026-10-19 10:58:41.776312177 +0300
+++ ../lib/googlecloudsdk/api_lib/dns/resource_record_sets.py	2026-10-19 10:59:37.289900533 +0300
@@ -27,7 +27,7 @@
 from googlecloudsdk.calliope import arg_parsers
 from googlecloudsdk.core import exceptions
 from googlecloudsdk.core import resources
-import ipaddr
+import ipaddress
 
 
 class UnsupportedRecordType(exceptions.Error):
@@ -321,7 +321,7 @@
 def IsIPv4(ip: str) -> bool:
   """Returns True if ip is an IPv4."""
   try:
-    ipaddr.IPv4Address(ip)
+    ipaddress.IPv4Address(ip)
     return True
   except ValueError:
     return False
@@ -330,7 +330,7 @@
 def IsIPv6(ip: str) -> bool:
   """Returns True if ip is an IPv6."""
   try:
-    ipaddr.IPv6Address(ip)
+    ipaddress.IPv6Address(ip)
     return True
   except ValueError:
     return False
--- ../lib/surface/compute/addresses/create.py	2026-10-19 11:02:55.002110471 +0300
+++ ../lib/surface/compute/addresses/create.py	2026-10-19 11:03:42.135901721 +0300
@@ -22,7 +22,7 @@
 from googlecloudsdk.calliope import exceptions
 from googlecloudsdk.command_lib.compute import flags as compute_flags
 from googlecloudsdk.command_lib.compute.addresses import flags
-import ipaddr
+import ipaddress
 from six.moves import zip  # pylint: disable=redefined-builtin
 
 
@@ -334,7 +334,7 @@
 
     if address is not None:
       try:
-        ip_address = ipaddr.IPAddress(address)
+        ip_address = ipaddress.ip_address(address)
       except ValueError:
         raise exceptions.InvalidArgumentException(
             '--addresses', 'Invalid IP address {e}'.format(e=address)
--- ../lib/googlecloudsdk/appengine/tools/dos_xml_parser.py	2026-10-19 11:06:55.978942317 +0300
+++ ../lib/googlecloudsdk/appengine/tools/dos_xml_parser.py	2026-10-19 11:07:40.361118290 +0300
@@ -30,7 +30,7 @@
 
 from googlecloudsdk.appengine.tools import xml_parser_utils
 from googlecloudsdk.appengine.tools.app_engine_config_exception import AppEngineConfigException
-import ipaddr
+import ipaddress
 
 MISSING_SUBNET = '<blacklist> node must have a subnet specified'
 BAD_IPV_SUBNET = '"%s" is not a valid IPv4 or IPv6 subnet'
@@ -114,7 +114,7 @@
     if not entry.subnet:
       return MISSING_SUBNET
     try:
-      ipaddr.IPNetwork(entry.subnet)
+      ipaddress.ip_network(entry.subnet, strict=False)
     except ValueError:
       return BAD_IPV_SUBNET % entry.subnet
     parts = entry.subnet.split('/')
--- ../lib/googlecloudsdk/appengine/api/dosinfo.py	2026-10-19 11:11:18.295249216 +0300
+++ ../lib/googlecloudsdk/appengine/api/dosinfo.py	2026-10-19 11:12:22.567705622 +0300
@@ -26,18 +26,12 @@
 # information in docstrings.  If you must communicate internal information in
 # this source file, please place them in comments only.
 
+import ipaddress
 import os
 import re
 
 from googlecloudsdk.appengine._internal import six_subset
 
-# ipaddr is py2-only, so conditionally import based on python version. See
-# comments under SubnetValidator.Validate for more context.
-if six_subset.PY2:
-  import ipaddr  # pylint:disable=g-import-not-at-top
-else:
-  ipaddr = None
-
 # pylint: disable=g-import-not-at-top
 if os.environ.get('APPENGINE_RUNTIME') == 'python27':
   from google.appengine.api import appinfo
@@ -70,14 +64,11 @@
     if not isinstance(value, six_subset.string_types):
       raise validation.ValidationError('subnet must be a string, not \'%r\'' %
                                        type(value))
-    # If we're running on py3 and don't have access to the ipaddr module,
-    # then the server will still do the validation on the IP address.
-    if ipaddr:
-      try:
-        ipaddr.IPNetwork(value)
-      except ValueError:
-        raise validation.ValidationError(
-            '%s is not a valid IPv4 or IPv6 subnet' % value)
+    try:
+      ipaddress.ip_network(value, strict=False)
+    except ValueError:
+      raise validation.ValidationError(
+          '%s is not a valid IPv4 or IPv6 subnet' % value)
 
     # Extra validation check since ipaddr accepts quad-dotted subnet masks.
     parts = value.split('/')
