@@ -1322,18 +1322,41 @@ def is_reserved(self):
1322
1322
@property
1323
1323
@functools .lru_cache ()
1324
1324
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:
1326
1328
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
1330
1335
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``.
1331
1338
"""
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
+ )
1333
1343
1334
1344
@property
1335
1345
@functools .lru_cache ()
1336
1346
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
+ """
1337
1360
return self not in self ._constants ._public_network and not self .is_private
1338
1361
1339
1362
@property
@@ -1537,13 +1560,15 @@ class _IPv4Constants:
1537
1560
1538
1561
_public_network = IPv4Network ('100.64.0.0/10' )
1539
1562
1563
+ # Not globally reachable address blocks listed on
1564
+ # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
1540
1565
_private_networks = [
1541
1566
IPv4Network ('0.0.0.0/8' ),
1542
1567
IPv4Network ('10.0.0.0/8' ),
1543
1568
IPv4Network ('127.0.0.0/8' ),
1544
1569
IPv4Network ('169.254.0.0/16' ),
1545
1570
IPv4Network ('172.16.0.0/12' ),
1546
- IPv4Network ('192.0.0.0/29 ' ),
1571
+ IPv4Network ('192.0.0.0/24 ' ),
1547
1572
IPv4Network ('192.0.0.170/31' ),
1548
1573
IPv4Network ('192.0.2.0/24' ),
1549
1574
IPv4Network ('192.168.0.0/16' ),
@@ -1554,6 +1579,11 @@ class _IPv4Constants:
1554
1579
IPv4Network ('255.255.255.255/32' ),
1555
1580
]
1556
1581
1582
+ _private_networks_exceptions = [
1583
+ IPv4Network ('192.0.0.9/32' ),
1584
+ IPv4Network ('192.0.0.10/32' ),
1585
+ ]
1586
+
1557
1587
_reserved_network = IPv4Network ('240.0.0.0/4' )
1558
1588
1559
1589
_unspecified_address = IPv4Address ('0.0.0.0' )
@@ -1995,23 +2025,42 @@ def is_site_local(self):
1995
2025
@property
1996
2026
@functools .lru_cache ()
1997
2027
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:
1999
2031
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
2003
2038
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``.
2004
2041
"""
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
+ )
2006
2049
2007
2050
@property
2008
2051
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:
2010
2055
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
2014
2061
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``.
2015
2064
"""
2016
2065
return not self .is_private
2017
2066
@@ -2252,19 +2301,31 @@ class _IPv6Constants:
2252
2301
2253
2302
_multicast_network = IPv6Network ('ff00::/8' )
2254
2303
2304
+ # Not globally reachable address blocks listed on
2305
+ # https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
2255
2306
_private_networks = [
2256
2307
IPv6Network ('::1/128' ),
2257
2308
IPv6Network ('::/128' ),
2258
2309
IPv6Network ('::ffff:0:0/96' ),
2310
+ IPv6Network ('64:ff9b:1::/48' ),
2259
2311
IPv6Network ('100::/64' ),
2260
2312
IPv6Network ('2001::/23' ),
2261
- IPv6Network ('2001:2::/48' ),
2262
2313
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' ),
2264
2316
IPv6Network ('fc00::/7' ),
2265
2317
IPv6Network ('fe80::/10' ),
2266
2318
]
2267
2319
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
+
2268
2329
_reserved_networks = [
2269
2330
IPv6Network ('::/8' ), IPv6Network ('100::/8' ),
2270
2331
IPv6Network ('200::/7' ), IPv6Network ('400::/6' ),
0 commit comments