Skip to content

Commit 6def623

Browse files
committed
Add fec0::/10 to IPv6 reserved networks and deprecate is_site_local
1 parent 8270ae5 commit 6def623

3 files changed

Lines changed: 57 additions & 17 deletions

File tree

Doc/library/ipaddress.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,9 @@ write code that handles both IP versions correctly. Address objects are
246246
.. note:: For IPv4, ``is_reserved`` is not related to the address block value of the
247247
``Reserved-by-Protocol`` column in iana-ipv4-special-registry_.
248248

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

252253
.. attribute:: is_loopback
253254

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

369+
.. deprecated:: next
370+
Site-local addresses (``fec0::/10``) were deprecated by :rfc:`3879`.
371+
Use :attr:`~IPv6Address.is_private` instead. This attribute is
372+
slated for removal in Python 3.21.
373+
368374
.. attribute:: ipv4_mapped
369375

370376
For addresses that appear to be IPv4 mapped addresses in the range
@@ -800,6 +806,11 @@ dictionaries.
800806
This attribute is true for the network as a whole if it is true
801807
for both the network address and the broadcast address.
802808

809+
.. deprecated:: next
810+
Site-local addresses (``fec0::/10``) were deprecated by :rfc:`3879`.
811+
Use :attr:`~IPv6Network.is_private` instead. This attribute is
812+
slated for removal in Python 3.21.
813+
803814

804815
Operators
805816
^^^^^^^^^

Lib/ipaddress.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
import functools
1212

13+
lazy import warnings
14+
15+
1316
IPV4LENGTH = 32
1417
IPV6LENGTH = 128
1518

@@ -2083,6 +2086,13 @@ def is_site_local(self):
20832086
A boolean, True if the address is reserved per RFC 3513 2.5.6.
20842087
20852088
"""
2089+
warnings._deprecated(
2090+
"IPv6Address.is_site_local",
2091+
"{name!r} is deprecated and slated for removal in Python "
2092+
"{remove}; site-local addresses (fec0::/10) were deprecated by "
2093+
"RFC 3879, use is_private instead",
2094+
remove=(3, 21),
2095+
)
20862096
return self in self._constants._sitelocal_network
20872097

20882098
@property
@@ -2363,8 +2373,16 @@ def is_site_local(self):
23632373
A boolean, True if the address is reserved per RFC 3513 2.5.6.
23642374
23652375
"""
2366-
return (self.network_address.is_site_local and
2367-
self.broadcast_address.is_site_local)
2376+
warnings._deprecated(
2377+
"IPv6Network.is_site_local",
2378+
"{name!r} is deprecated and slated for removal in Python "
2379+
"{remove}; site-local addresses (fec0::/10) were deprecated by "
2380+
"RFC 3879, use is_private instead",
2381+
remove=(3, 21),
2382+
)
2383+
sitelocal_network = self._constants._sitelocal_network
2384+
return (self.network_address in sitelocal_network and
2385+
self.broadcast_address in sitelocal_network)
23682386

23692387

23702388
class _IPv6Constants:
@@ -2408,7 +2426,7 @@ class _IPv6Constants:
24082426
IPv6Network('8000::/3'), IPv6Network('A000::/3'),
24092427
IPv6Network('C000::/3'), IPv6Network('E000::/4'),
24102428
IPv6Network('F000::/5'), IPv6Network('F800::/6'),
2411-
IPv6Network('FE00::/9'),
2429+
IPv6Network('FE00::/9'), IPv6Network('FEC0::/10'),
24122430
]
24132431

24142432
_sitelocal_network = IPv6Network('fec0::/10')

Lib/test/test_ipaddress.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,12 +2418,16 @@ def testReservedIpv6(self):
24182418
self.assertEqual(True, ipaddress.ip_network('ff00::').is_multicast)
24192419
self.assertEqual(False, ipaddress.ip_network('fdff::').is_multicast)
24202420

2421-
self.assertEqual(True, ipaddress.ip_network('fecf::').is_site_local)
2422-
self.assertEqual(True, ipaddress.ip_network(
2423-
'feff:ffff:ffff:ffff::').is_site_local)
2424-
self.assertEqual(False, ipaddress.ip_network(
2425-
'fbf:ffff::').is_site_local)
2426-
self.assertEqual(False, ipaddress.ip_network('ff00::').is_site_local)
2421+
with self.assertWarns(DeprecationWarning):
2422+
self.assertEqual(True, ipaddress.ip_network('fecf::').is_site_local)
2423+
with self.assertWarns(DeprecationWarning):
2424+
self.assertEqual(True, ipaddress.ip_network(
2425+
'feff:ffff:ffff:ffff::').is_site_local)
2426+
with self.assertWarns(DeprecationWarning):
2427+
self.assertEqual(False, ipaddress.ip_network(
2428+
'fbf:ffff::').is_site_local)
2429+
with self.assertWarns(DeprecationWarning):
2430+
self.assertEqual(False, ipaddress.ip_network('ff00::').is_site_local)
24272431

24282432
self.assertEqual(True, ipaddress.ip_network('fc00::').is_private)
24292433
self.assertEqual(True, ipaddress.ip_network(
@@ -2457,12 +2461,16 @@ def testReservedIpv6(self):
24572461
self.assertEqual(True, ipaddress.ip_address('ff00::').is_multicast)
24582462
self.assertEqual(False, ipaddress.ip_address('fdff::').is_multicast)
24592463

2460-
self.assertEqual(True, ipaddress.ip_address('fecf::').is_site_local)
2461-
self.assertEqual(True, ipaddress.ip_address(
2462-
'feff:ffff:ffff:ffff::').is_site_local)
2463-
self.assertEqual(False, ipaddress.ip_address(
2464-
'fbf:ffff::').is_site_local)
2465-
self.assertEqual(False, ipaddress.ip_address('ff00::').is_site_local)
2464+
with self.assertWarns(DeprecationWarning):
2465+
self.assertEqual(True, ipaddress.ip_address('fecf::').is_site_local)
2466+
with self.assertWarns(DeprecationWarning):
2467+
self.assertEqual(True, ipaddress.ip_address(
2468+
'feff:ffff:ffff:ffff::').is_site_local)
2469+
with self.assertWarns(DeprecationWarning):
2470+
self.assertEqual(False, ipaddress.ip_address(
2471+
'fbf:ffff::').is_site_local)
2472+
with self.assertWarns(DeprecationWarning):
2473+
self.assertEqual(False, ipaddress.ip_address('ff00::').is_site_local)
24662474

24672475
self.assertEqual(True, ipaddress.ip_address('fc00::').is_private)
24682476
self.assertEqual(True, ipaddress.ip_address(
@@ -2503,6 +2511,9 @@ def testReservedIpv6(self):
25032511
# some generic IETF reserved addresses
25042512
self.assertEqual(True, ipaddress.ip_address('100::').is_reserved)
25052513
self.assertEqual(True, ipaddress.ip_network('4000::1/128').is_reserved)
2514+
# gh-136832: fec0::/10 (former site-local prefix) is reserved
2515+
self.assertEqual(True, ipaddress.ip_address('fec0::1').is_reserved)
2516+
self.assertEqual(True, ipaddress.ip_network('fec0::/10').is_reserved)
25062517

25072518
def testIpv4Mapped(self):
25082519
self.assertEqual(

0 commit comments

Comments
 (0)