@@ -1302,18 +1302,41 @@ def is_reserved(self):
13021302 @property
13031303 @functools .lru_cache ()
13041304 def is_private (self ):
1305- """Test if this address is allocated for private networks.
1305+ """``True`` if the address is defined as not globally reachable by
1306+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1307+ (for IPv6) with the following exceptions:
13061308
1307- Returns:
1308- A boolean, True if the address is reserved per
1309- iana-ipv4-special-registry.
1309+ * ``is_private`` is ``False`` for ``100.64.0.0/10``
1310+ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1311+ semantics of the underlying IPv4 addresses and the following condition holds
1312+ (see :attr:`IPv6Address.ipv4_mapped`)::
1313+
1314+ address.is_private == address.ipv4_mapped.is_private
13101315
1316+ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10``
1317+ IPv4 range where they are both ``False``.
13111318 """
1312- return any (self in net for net in self ._constants ._private_networks )
1319+ return (
1320+ any (self in net for net in self ._constants ._private_networks )
1321+ and all (self not in net for net in self ._constants ._private_networks_exceptions )
1322+ )
13131323
13141324 @property
13151325 @functools .lru_cache ()
13161326 def is_global (self ):
1327+ """``True`` if the address is defined as globally reachable by
1328+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1329+ (for IPv6) with the following exception:
1330+
1331+ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1332+ semantics of the underlying IPv4 addresses and the following condition holds
1333+ (see :attr:`IPv6Address.ipv4_mapped`)::
1334+
1335+ address.is_global == address.ipv4_mapped.is_global
1336+
1337+ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10``
1338+ IPv4 range where they are both ``False``.
1339+ """
13171340 return self not in self ._constants ._public_network and not self .is_private
13181341
13191342 @property
@@ -1548,13 +1571,15 @@ class _IPv4Constants:
15481571
15491572 _public_network = IPv4Network ('100.64.0.0/10' )
15501573
1574+ # Not globally reachable address blocks listed on
1575+ # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
15511576 _private_networks = [
15521577 IPv4Network ('0.0.0.0/8' ),
15531578 IPv4Network ('10.0.0.0/8' ),
15541579 IPv4Network ('127.0.0.0/8' ),
15551580 IPv4Network ('169.254.0.0/16' ),
15561581 IPv4Network ('172.16.0.0/12' ),
1557- IPv4Network ('192.0.0.0/29 ' ),
1582+ IPv4Network ('192.0.0.0/24 ' ),
15581583 IPv4Network ('192.0.0.170/31' ),
15591584 IPv4Network ('192.0.2.0/24' ),
15601585 IPv4Network ('192.168.0.0/16' ),
@@ -1565,6 +1590,11 @@ class _IPv4Constants:
15651590 IPv4Network ('255.255.255.255/32' ),
15661591 ]
15671592
1593+ _private_networks_exceptions = [
1594+ IPv4Network ('192.0.0.9/32' ),
1595+ IPv4Network ('192.0.0.10/32' ),
1596+ ]
1597+
15681598 _reserved_network = IPv4Network ('240.0.0.0/4' )
15691599
15701600 _unspecified_address = IPv4Address ('0.0.0.0' )
@@ -1953,23 +1983,42 @@ def is_site_local(self):
19531983 @property
19541984 @functools .lru_cache ()
19551985 def is_private (self ):
1956- """Test if this address is allocated for private networks.
1986+ """``True`` if the address is defined as not globally reachable by
1987+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1988+ (for IPv6) with the following exceptions:
19571989
1958- Returns:
1959- A boolean, True if the address is reserved per
1960- iana-ipv6-special-registry.
1990+ * ``is_private`` is ``False`` for ``100.64.0.0/10``
1991+ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1992+ semantics of the underlying IPv4 addresses and the following condition holds
1993+ (see :attr:`IPv6Address.ipv4_mapped`)::
1994+
1995+ address.is_private == address.ipv4_mapped.is_private
19611996
1997+ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10``
1998+ IPv4 range where they are both ``False``.
19621999 """
1963- return any (self in net for net in self ._constants ._private_networks )
2000+ ipv4_mapped = self .ipv4_mapped
2001+ if ipv4_mapped is not None :
2002+ return ipv4_mapped .is_private
2003+ return (
2004+ any (self in net for net in self ._constants ._private_networks )
2005+ and all (self not in net for net in self ._constants ._private_networks_exceptions )
2006+ )
19642007
19652008 @property
19662009 def is_global (self ):
1967- """Test if this address is allocated for public networks.
2010+ """``True`` if the address is defined as globally reachable by
2011+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
2012+ (for IPv6) with the following exception:
19682013
1969- Returns:
1970- A boolean, true if the address is not reserved per
1971- iana-ipv6-special-registry.
2014+ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
2015+ semantics of the underlying IPv4 addresses and the following condition holds
2016+ (see :attr:`IPv6Address.ipv4_mapped`)::
2017+
2018+ address.is_global == address.ipv4_mapped.is_global
19722019
2020+ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10``
2021+ IPv4 range where they are both ``False``.
19732022 """
19742023 return not self .is_private
19752024
@@ -2236,19 +2285,31 @@ class _IPv6Constants:
22362285
22372286 _multicast_network = IPv6Network ('ff00::/8' )
22382287
2288+ # Not globally reachable address blocks listed on
2289+ # https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
22392290 _private_networks = [
22402291 IPv6Network ('::1/128' ),
22412292 IPv6Network ('::/128' ),
22422293 IPv6Network ('::ffff:0:0/96' ),
2294+ IPv6Network ('64:ff9b:1::/48' ),
22432295 IPv6Network ('100::/64' ),
22442296 IPv6Network ('2001::/23' ),
2245- IPv6Network ('2001:2::/48' ),
22462297 IPv6Network ('2001:db8::/32' ),
2247- IPv6Network ('2001:10::/28' ),
2298+ # IANA says N/A, let's consider it not globally reachable to be safe
2299+ IPv6Network ('2002::/16' ),
22482300 IPv6Network ('fc00::/7' ),
22492301 IPv6Network ('fe80::/10' ),
22502302 ]
22512303
2304+ _private_networks_exceptions = [
2305+ IPv6Network ('2001:1::1/128' ),
2306+ IPv6Network ('2001:1::2/128' ),
2307+ IPv6Network ('2001:3::/32' ),
2308+ IPv6Network ('2001:4:112::/48' ),
2309+ IPv6Network ('2001:20::/28' ),
2310+ IPv6Network ('2001:30::/28' ),
2311+ ]
2312+
22522313 _reserved_networks = [
22532314 IPv6Network ('::/8' ), IPv6Network ('100::/8' ),
22542315 IPv6Network ('200::/7' ), IPv6Network ('400::/6' ),
0 commit comments