@@ -1322,18 +1322,41 @@ def is_reserved(self):
13221322 @property
13231323 @functools .lru_cache ()
13241324 def is_private (self ):
1325- """Test if this address is allocated for private networks.
1325+ """``True`` if the address is defined as not globally reachable by
1326+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1327+ (for IPv6) with the following exceptions:
13261328
1327- Returns:
1328- A boolean, True if the address is reserved per
1329- iana-ipv4-special-registry.
1329+ * ``is_private`` is ``False`` for ``100.64.0.0/10``
1330+ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1331+ semantics of the underlying IPv4 addresses and the following condition holds
1332+ (see :attr:`IPv6Address.ipv4_mapped`)::
1333+
1334+ address.is_private == address.ipv4_mapped.is_private
13301335
1336+ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10``
1337+ IPv4 range where they are both ``False``.
13311338 """
1332- return any (self in net for net in self ._constants ._private_networks )
1339+ return (
1340+ any (self in net for net in self ._constants ._private_networks )
1341+ and all (self not in net for net in self ._constants ._private_networks_exceptions )
1342+ )
13331343
13341344 @property
13351345 @functools .lru_cache ()
13361346 def is_global (self ):
1347+ """``True`` if the address is defined as globally reachable by
1348+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1349+ (for IPv6) with the following exception:
1350+
1351+ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1352+ semantics of the underlying IPv4 addresses and the following condition holds
1353+ (see :attr:`IPv6Address.ipv4_mapped`)::
1354+
1355+ address.is_global == address.ipv4_mapped.is_global
1356+
1357+ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10``
1358+ IPv4 range where they are both ``False``.
1359+ """
13371360 return self not in self ._constants ._public_network and not self .is_private
13381361
13391362 @property
@@ -1537,13 +1560,15 @@ class _IPv4Constants:
15371560
15381561 _public_network = IPv4Network ('100.64.0.0/10' )
15391562
1563+ # Not globally reachable address blocks listed on
1564+ # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
15401565 _private_networks = [
15411566 IPv4Network ('0.0.0.0/8' ),
15421567 IPv4Network ('10.0.0.0/8' ),
15431568 IPv4Network ('127.0.0.0/8' ),
15441569 IPv4Network ('169.254.0.0/16' ),
15451570 IPv4Network ('172.16.0.0/12' ),
1546- IPv4Network ('192.0.0.0/29 ' ),
1571+ IPv4Network ('192.0.0.0/24 ' ),
15471572 IPv4Network ('192.0.0.170/31' ),
15481573 IPv4Network ('192.0.2.0/24' ),
15491574 IPv4Network ('192.168.0.0/16' ),
@@ -1554,6 +1579,11 @@ class _IPv4Constants:
15541579 IPv4Network ('255.255.255.255/32' ),
15551580 ]
15561581
1582+ _private_networks_exceptions = [
1583+ IPv4Network ('192.0.0.9/32' ),
1584+ IPv4Network ('192.0.0.10/32' ),
1585+ ]
1586+
15571587 _reserved_network = IPv4Network ('240.0.0.0/4' )
15581588
15591589 _unspecified_address = IPv4Address ('0.0.0.0' )
@@ -1995,23 +2025,42 @@ def is_site_local(self):
19952025 @property
19962026 @functools .lru_cache ()
19972027 def is_private (self ):
1998- """Test if this address is allocated for private networks.
2028+ """``True`` if the address is defined as not globally reachable by
2029+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
2030+ (for IPv6) with the following exceptions:
19992031
2000- Returns:
2001- A boolean, True if the address is reserved per
2002- iana-ipv6-special-registry.
2032+ * ``is_private`` is ``False`` for ``100.64.0.0/10``
2033+ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
2034+ semantics of the underlying IPv4 addresses and the following condition holds
2035+ (see :attr:`IPv6Address.ipv4_mapped`)::
2036+
2037+ address.is_private == address.ipv4_mapped.is_private
20032038
2039+ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10``
2040+ IPv4 range where they are both ``False``.
20042041 """
2005- return any (self in net for net in self ._constants ._private_networks )
2042+ ipv4_mapped = self .ipv4_mapped
2043+ if ipv4_mapped is not None :
2044+ return ipv4_mapped .is_private
2045+ return (
2046+ any (self in net for net in self ._constants ._private_networks )
2047+ and all (self not in net for net in self ._constants ._private_networks_exceptions )
2048+ )
20062049
20072050 @property
20082051 def is_global (self ):
2009- """Test if this address is allocated for public networks.
2052+ """``True`` if the address is defined as globally reachable by
2053+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
2054+ (for IPv6) with the following exception:
20102055
2011- Returns:
2012- A boolean, true if the address is not reserved per
2013- iana-ipv6-special-registry.
2056+ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
2057+ semantics of the underlying IPv4 addresses and the following condition holds
2058+ (see :attr:`IPv6Address.ipv4_mapped`)::
2059+
2060+ address.is_global == address.ipv4_mapped.is_global
20142061
2062+ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10``
2063+ IPv4 range where they are both ``False``.
20152064 """
20162065 return not self .is_private
20172066
@@ -2252,19 +2301,31 @@ class _IPv6Constants:
22522301
22532302 _multicast_network = IPv6Network ('ff00::/8' )
22542303
2304+ # Not globally reachable address blocks listed on
2305+ # https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
22552306 _private_networks = [
22562307 IPv6Network ('::1/128' ),
22572308 IPv6Network ('::/128' ),
22582309 IPv6Network ('::ffff:0:0/96' ),
2310+ IPv6Network ('64:ff9b:1::/48' ),
22592311 IPv6Network ('100::/64' ),
22602312 IPv6Network ('2001::/23' ),
2261- IPv6Network ('2001:2::/48' ),
22622313 IPv6Network ('2001:db8::/32' ),
2263- IPv6Network ('2001:10::/28' ),
2314+ # IANA says N/A, let's consider it not globally reachable to be safe
2315+ IPv6Network ('2002::/16' ),
22642316 IPv6Network ('fc00::/7' ),
22652317 IPv6Network ('fe80::/10' ),
22662318 ]
22672319
2320+ _private_networks_exceptions = [
2321+ IPv6Network ('2001:1::1/128' ),
2322+ IPv6Network ('2001:1::2/128' ),
2323+ IPv6Network ('2001:3::/32' ),
2324+ IPv6Network ('2001:4:112::/48' ),
2325+ IPv6Network ('2001:20::/28' ),
2326+ IPv6Network ('2001:30::/28' ),
2327+ ]
2328+
22682329 _reserved_networks = [
22692330 IPv6Network ('::/8' ), IPv6Network ('100::/8' ),
22702331 IPv6Network ('200::/7' ), IPv6Network ('400::/6' ),
0 commit comments