Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions Doc/library/ipaddress.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,9 @@ write code that handles both IP versions correctly. Address objects are
.. note:: For IPv4, ``is_reserved`` is not related to the address block value of the
``Reserved-by-Protocol`` column in iana-ipv4-special-registry_.

.. caution:: For IPv6, ``fec0::/10`` a former Site-Local scoped address prefix is
currently excluded from that list (see :attr:`~IPv6Address.is_site_local` & :rfc:`3879`).
.. versionchanged:: next
For IPv6, ``fec0::/10`` (the former Site-Local scoped address prefix
deprecated by :rfc:`3879`) is now included in the reserved range.

.. attribute:: is_loopback

Expand Down Expand Up @@ -365,6 +366,10 @@ write code that handles both IP versions correctly. Address objects are
:attr:`~IPv4Address.is_private` to test if this address is in the
space of unique local addresses as defined by :RFC:`4193`.

.. deprecated-removed:: next 3.21
Site-local addresses (``fec0::/10``) were deprecated by :rfc:`3879`.
Use :attr:`~IPv6Address.is_private` instead.

.. attribute:: ipv4_mapped

For addresses that appear to be IPv4 mapped addresses in the range
Expand Down Expand Up @@ -800,6 +805,10 @@ dictionaries.
This attribute is true for the network as a whole if it is true
for both the network address and the broadcast address.

.. deprecated-removed:: next 3.21
Site-local addresses (``fec0::/10``) were deprecated by :rfc:`3879`.
Use :attr:`~IPv6Network.is_private` instead.


Operators
^^^^^^^^^
Expand Down
24 changes: 21 additions & 3 deletions Lib/ipaddress.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

import functools

lazy import warnings


IPV4LENGTH = 32
IPV6LENGTH = 128

Expand Down Expand Up @@ -2083,6 +2086,13 @@ def is_site_local(self):
A boolean, True if the address is reserved per RFC 3513 2.5.6.

"""
warnings._deprecated(
"IPv6Address.is_site_local",
"{name!r} is deprecated and slated for removal in Python "
"{remove}; site-local addresses (fec0::/10) were deprecated by "
"RFC 3879, use is_private instead",
remove=(3, 21),
)
return self in self._constants._sitelocal_network

@property
Expand Down Expand Up @@ -2363,8 +2373,16 @@ def is_site_local(self):
A boolean, True if the address is reserved per RFC 3513 2.5.6.

"""
return (self.network_address.is_site_local and
self.broadcast_address.is_site_local)
warnings._deprecated(
"IPv6Network.is_site_local",
"{name!r} is deprecated and slated for removal in Python "
"{remove}; site-local addresses (fec0::/10) were deprecated by "
"RFC 3879, use is_private instead",
remove=(3, 21),
)
sitelocal_network = self._constants._sitelocal_network
return (self.network_address in sitelocal_network and
self.broadcast_address in sitelocal_network)


class _IPv6Constants:
Expand Down Expand Up @@ -2408,7 +2426,7 @@ class _IPv6Constants:
IPv6Network('8000::/3'), IPv6Network('A000::/3'),
IPv6Network('C000::/3'), IPv6Network('E000::/4'),
IPv6Network('F000::/5'), IPv6Network('F800::/6'),
IPv6Network('FE00::/9'),
IPv6Network('FE00::/9'), IPv6Network('FEC0::/10'),
]

_sitelocal_network = IPv6Network('fec0::/10')
Expand Down
29 changes: 17 additions & 12 deletions Lib/test/test_ipaddress.py
Original file line number Diff line number Diff line change
Expand Up @@ -2418,12 +2418,13 @@ def testReservedIpv6(self):
self.assertEqual(True, ipaddress.ip_network('ff00::').is_multicast)
self.assertEqual(False, ipaddress.ip_network('fdff::').is_multicast)

self.assertEqual(True, ipaddress.ip_network('fecf::').is_site_local)
self.assertEqual(True, ipaddress.ip_network(
'feff:ffff:ffff:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_network(
'fbf:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_network('ff00::').is_site_local)
with self.assertWarns(DeprecationWarning):
self.assertEqual(True, ipaddress.ip_network('fecf::').is_site_local)
self.assertEqual(True, ipaddress.ip_network(
'feff:ffff:ffff:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_network(
'fbf:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_network('ff00::').is_site_local)

self.assertEqual(True, ipaddress.ip_network('fc00::').is_private)
self.assertEqual(True, ipaddress.ip_network(
Expand Down Expand Up @@ -2457,12 +2458,13 @@ def testReservedIpv6(self):
self.assertEqual(True, ipaddress.ip_address('ff00::').is_multicast)
self.assertEqual(False, ipaddress.ip_address('fdff::').is_multicast)

self.assertEqual(True, ipaddress.ip_address('fecf::').is_site_local)
self.assertEqual(True, ipaddress.ip_address(
'feff:ffff:ffff:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_address(
'fbf:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_address('ff00::').is_site_local)
with self.assertWarns(DeprecationWarning):
self.assertEqual(True, ipaddress.ip_address('fecf::').is_site_local)
self.assertEqual(True, ipaddress.ip_address(
'feff:ffff:ffff:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_address(
'fbf:ffff::').is_site_local)
self.assertEqual(False, ipaddress.ip_address('ff00::').is_site_local)

self.assertEqual(True, ipaddress.ip_address('fc00::').is_private)
self.assertEqual(True, ipaddress.ip_address(
Expand Down Expand Up @@ -2503,6 +2505,9 @@ def testReservedIpv6(self):
# some generic IETF reserved addresses
self.assertEqual(True, ipaddress.ip_address('100::').is_reserved)
self.assertEqual(True, ipaddress.ip_network('4000::1/128').is_reserved)
# gh-136832: fec0::/10 (former site-local prefix) is reserved
self.assertEqual(True, ipaddress.ip_address('fec0::1').is_reserved)
self.assertEqual(True, ipaddress.ip_network('fec0::/10').is_reserved)

def testIpv4Mapped(self):
self.assertEqual(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
The IPv6 address block ``fec0::/10`` (the former Site-Local scoped address
prefix deprecated by :rfc:`3879`) is now reported as reserved by
:attr:`ipaddress.IPv6Address.is_reserved`. The
:attr:`~ipaddress.IPv6Address.is_site_local` and
:attr:`~ipaddress.IPv6Network.is_site_local` attributes are now deprecated
and slated for removal in Python 3.21; use
:attr:`~ipaddress.IPv6Address.is_private` instead.
Loading