Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit895f7e2

Browse files
encukoujstasiak
andauthored
[3.8]gh-113171:gh-65056: Fix "private" (non-global) IP address ranges (GH-113179) (GH-113186) (GH-118177) (GH-118479)
The _private_networks variables, used by various is_privateimplementations, were missing some ranges and at the same time hadoverly strict ranges (where there are more specific ranges consideredglobally reachable by the IANA registries).This patch updates the ranges with what was missing or otherwiseincorrect.100.64.0.0/10 is left alone, for now, as it's been made special in [1].The _address_exclude_many() call returns 8 networks for IPv4, 121networks for IPv6.[1]#61602In 3.10 and below, is_private checks whether the network and broadcastaddress are both private.In later versions (where the test wss backported from), it checkswhether they both are in the same private network.For 0.0.0.0/0, both 0.0.0.0 and 255.225.255.255 are private,but one is in 0.0.0.0/8 ("This network") and the other in255.255.255.255/32 ("Limited broadcast").---------Co-authored-by: Jakub Stasiak <jakub@stasiak.at>
1 parentf791cda commit895f7e2

File tree

6 files changed

+195
-21
lines changed

6 files changed

+195
-21
lines changed

‎Doc/library/ipaddress.rst

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,18 +179,53 @@ write code that handles both IP versions correctly. Address objects are
179179

180180
..attribute::is_private
181181

182-
``True`` if the address isallocated for private networks. See
182+
``True`` if the address isdefined as not globally reachable by
183183
iana-ipv4-special-registry_ (for IPv4) oriana-ipv6-special-registry_
184-
(for IPv6).
184+
(for IPv6) with the following exceptions:
185+
186+
* ``is_private`` is ``False`` for the shared address space (``100.64.0.0/10``)
187+
* For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
188+
semantics of the underlying IPv4 addresses and the following condition holds
189+
(see:attr:`IPv6Address.ipv4_mapped`)::
190+
191+
address.is_private == address.ipv4_mapped.is_private
192+
193+
``is_private`` has value opposite to:attr:`is_global`, except for the shared address space
194+
(``100.64.0.0/10`` range) where they are both ``False``.
195+
196+
..versionchanged::3.8.20
197+
198+
Fixed some false positives and false negatives.
199+
200+
* ``192.0.0.0/24`` is considered private with the exception of ``192.0.0.9/32`` and
201+
``192.0.0.10/32`` (previously: only the ``192.0.0.0/29`` sub-range was considered private).
202+
* ``64:ff9b:1::/48`` is considered private.
203+
* ``2002::/16`` is considered private.
204+
* There are exceptions within ``2001::/23`` (otherwise considered private): ``2001:1::1/128``,
205+
``2001:1::2/128``, ``2001:3::/32``, ``2001:4:112::/48``, ``2001:20::/28``, ``2001:30::/28``.
206+
The exceptions are not considered private.
185207

186208
..attribute::is_global
187209

188-
``True`` if the address isallocated for public networks. See
210+
``True`` if the address isdefined as globally reachable by
189211
iana-ipv4-special-registry_ (for IPv4) oriana-ipv6-special-registry_
190-
(for IPv6).
212+
(for IPv6) with the following exception:
213+
214+
For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
215+
semantics of the underlying IPv4 addresses and the following condition holds
216+
(see:attr:`IPv6Address.ipv4_mapped`)::
217+
218+
address.is_global == address.ipv4_mapped.is_global
219+
220+
``is_global`` has value opposite to:attr:`is_private`, except for the shared address space
221+
(``100.64.0.0/10`` range) where they are both ``False``.
191222

192223
..versionadded::3.4
193224

225+
..versionchanged::3.8.20
226+
227+
Fixed some false positives and false negatives, see:attr:`is_private` for details.
228+
194229
..attribute::is_unspecified
195230

196231
``True`` if the address is unspecified. See:RFC:`5735` (for IPv4)

‎Doc/tools/susp-ignored.csv

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ library/ipaddress,,:db00,2001:db00::0/24
158158
library/ipaddress,,::,2001:db00::0/24
159159
library/ipaddress,,:db00,2001:db00::0/ffff:ff00::
160160
library/ipaddress,,::,2001:db00::0/ffff:ff00::
161+
library/ipaddress,,:ff9b,64:ff9b:1::/48
162+
library/ipaddress,,::,64:ff9b:1::/48
163+
library/ipaddress,,::,2001::
164+
library/ipaddress,,::,2001:1::
165+
library/ipaddress,,::,2001:3::
166+
library/ipaddress,,::,2001:4:112::
167+
library/ipaddress,,::,2001:20::
168+
library/ipaddress,,::,2001:30::
161169
library/itertools,,:step,elements from seq[start:stop:step]
162170
library/itertools,,:stop,elements from seq[start:stop:step]
163171
library/logging.handlers,,:port,host:port

‎Doc/whatsnew/3.8.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2355,3 +2355,12 @@ tarfile
23552355
:exc:`DeprecationWarning`.
23562356
In Python 3.14, the default will switch to ``'data'``.
23572357
(Contributed by Petr Viktorin in:pep:`706`.)
2358+
2359+
Notable changes in 3.8.20
2360+
=========================
2361+
2362+
ipaddress
2363+
---------
2364+
2365+
* Fixed ``is_global`` and ``is_private`` behavior in ``IPv4Address``,
2366+
``IPv6Address``, ``IPv4Network`` and ``IPv6Network``.

‎Lib/ipaddress.py

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,18 +1275,41 @@ def is_reserved(self):
12751275
@property
12761276
@functools.lru_cache()
12771277
defis_private(self):
1278-
"""Test if this address is allocated for private networks.
1278+
"""``True`` if the address is defined as not globally reachable by
1279+
iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1280+
(for IPv6) with the following exceptions:
12791281
1280-
Returns:
1281-
A boolean, True if the address is reserved per
1282-
iana-ipv4-special-registry.
1282+
* ``is_private`` is ``False`` for ``100.64.0.0/10``
1283+
* For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1284+
semantics of the underlying IPv4 addresses and the following condition holds
1285+
(see :attr:`IPv6Address.ipv4_mapped`)::
1286+
1287+
address.is_private == address.ipv4_mapped.is_private
12831288
1289+
``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10``
1290+
IPv4 range where they are both ``False``.
12841291
"""
1285-
returnany(selfinnetfornetinself._constants._private_networks)
1292+
return (
1293+
any(selfinnetfornetinself._constants._private_networks)
1294+
andall(selfnotinnetfornetinself._constants._private_networks_exceptions)
1295+
)
12861296

12871297
@property
12881298
@functools.lru_cache()
12891299
defis_global(self):
1300+
"""``True`` if the address is defined as globally reachable by
1301+
iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1302+
(for IPv6) with the following exception:
1303+
1304+
For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1305+
semantics of the underlying IPv4 addresses and the following condition holds
1306+
(see :attr:`IPv6Address.ipv4_mapped`)::
1307+
1308+
address.is_global == address.ipv4_mapped.is_global
1309+
1310+
``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10``
1311+
IPv4 range where they are both ``False``.
1312+
"""
12901313
returnselfnotinself._constants._public_networkandnotself.is_private
12911314

12921315
@property
@@ -1490,13 +1513,15 @@ class _IPv4Constants:
14901513

14911514
_public_network=IPv4Network('100.64.0.0/10')
14921515

1516+
# Not globally reachable address blocks listed on
1517+
# https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
14931518
_private_networks= [
14941519
IPv4Network('0.0.0.0/8'),
14951520
IPv4Network('10.0.0.0/8'),
14961521
IPv4Network('127.0.0.0/8'),
14971522
IPv4Network('169.254.0.0/16'),
14981523
IPv4Network('172.16.0.0/12'),
1499-
IPv4Network('192.0.0.0/29'),
1524+
IPv4Network('192.0.0.0/24'),
15001525
IPv4Network('192.0.0.170/31'),
15011526
IPv4Network('192.0.2.0/24'),
15021527
IPv4Network('192.168.0.0/16'),
@@ -1507,6 +1532,11 @@ class _IPv4Constants:
15071532
IPv4Network('255.255.255.255/32'),
15081533
]
15091534

1535+
_private_networks_exceptions= [
1536+
IPv4Network('192.0.0.9/32'),
1537+
IPv4Network('192.0.0.10/32'),
1538+
]
1539+
15101540
_reserved_network=IPv4Network('240.0.0.0/4')
15111541

15121542
_unspecified_address=IPv4Address('0.0.0.0')
@@ -1897,23 +1927,42 @@ def is_site_local(self):
18971927
@property
18981928
@functools.lru_cache()
18991929
defis_private(self):
1900-
"""Test if this address is allocated for private networks.
1930+
"""``True`` if the address is defined as not globally reachable by
1931+
iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1932+
(for IPv6) with the following exceptions:
19011933
1902-
Returns:
1903-
A boolean, True if the address is reserved per
1904-
iana-ipv6-special-registry.
1934+
* ``is_private`` is ``False`` for ``100.64.0.0/10``
1935+
* For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1936+
semantics of the underlying IPv4 addresses and the following condition holds
1937+
(see :attr:`IPv6Address.ipv4_mapped`)::
1938+
1939+
address.is_private == address.ipv4_mapped.is_private
19051940
1941+
``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10``
1942+
IPv4 range where they are both ``False``.
19061943
"""
1907-
returnany(selfinnetfornetinself._constants._private_networks)
1944+
ipv4_mapped=self.ipv4_mapped
1945+
ifipv4_mappedisnotNone:
1946+
returnipv4_mapped.is_private
1947+
return (
1948+
any(selfinnetfornetinself._constants._private_networks)
1949+
andall(selfnotinnetfornetinself._constants._private_networks_exceptions)
1950+
)
19081951

19091952
@property
19101953
defis_global(self):
1911-
"""Test if this address is allocated for public networks.
1954+
"""``True`` if the address is defined as globally reachable by
1955+
iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_
1956+
(for IPv6) with the following exception:
19121957
1913-
Returns:
1914-
A boolean, true if the address is not reserved per
1915-
iana-ipv6-special-registry.
1958+
For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the
1959+
semantics of the underlying IPv4 addresses and the following condition holds
1960+
(see :attr:`IPv6Address.ipv4_mapped`)::
1961+
1962+
address.is_global == address.ipv4_mapped.is_global
19161963
1964+
``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10``
1965+
IPv4 range where they are both ``False``.
19171966
"""
19181967
returnnotself.is_private
19191968

@@ -2154,19 +2203,31 @@ class _IPv6Constants:
21542203

21552204
_multicast_network=IPv6Network('ff00::/8')
21562205

2206+
# Not globally reachable address blocks listed on
2207+
# https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
21572208
_private_networks= [
21582209
IPv6Network('::1/128'),
21592210
IPv6Network('::/128'),
21602211
IPv6Network('::ffff:0:0/96'),
2212+
IPv6Network('64:ff9b:1::/48'),
21612213
IPv6Network('100::/64'),
21622214
IPv6Network('2001::/23'),
2163-
IPv6Network('2001:2::/48'),
21642215
IPv6Network('2001:db8::/32'),
2165-
IPv6Network('2001:10::/28'),
2216+
# IANA says N/A, let's consider it not globally reachable to be safe
2217+
IPv6Network('2002::/16'),
21662218
IPv6Network('fc00::/7'),
21672219
IPv6Network('fe80::/10'),
21682220
]
21692221

2222+
_private_networks_exceptions= [
2223+
IPv6Network('2001:1::1/128'),
2224+
IPv6Network('2001:1::2/128'),
2225+
IPv6Network('2001:3::/32'),
2226+
IPv6Network('2001:4:112::/48'),
2227+
IPv6Network('2001:20::/28'),
2228+
IPv6Network('2001:30::/28'),
2229+
]
2230+
21702231
_reserved_networks= [
21712232
IPv6Network('::/8'),IPv6Network('100::/8'),
21722233
IPv6Network('200::/7'),IPv6Network('400::/6'),

‎Lib/test/test_ipaddress.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,10 @@ def testReservedIpv4(self):
17611761
self.assertEqual(True,ipaddress.ip_address(
17621762
'172.31.255.255').is_private)
17631763
self.assertEqual(False,ipaddress.ip_address('172.32.0.0').is_private)
1764+
self.assertFalse(ipaddress.ip_address('192.0.0.0').is_global)
1765+
self.assertTrue(ipaddress.ip_address('192.0.0.9').is_global)
1766+
self.assertTrue(ipaddress.ip_address('192.0.0.10').is_global)
1767+
self.assertFalse(ipaddress.ip_address('192.0.0.255').is_global)
17641768

17651769
self.assertEqual(True,
17661770
ipaddress.ip_address('169.254.100.200').is_link_local)
@@ -1776,6 +1780,40 @@ def testReservedIpv4(self):
17761780
self.assertEqual(False,ipaddress.ip_address('128.0.0.0').is_loopback)
17771781
self.assertEqual(True,ipaddress.ip_network('0.0.0.0').is_unspecified)
17781782

1783+
deftestPrivateNetworks(self):
1784+
self.assertEqual(True,ipaddress.ip_network("0.0.0.0/0").is_private)
1785+
self.assertEqual(False,ipaddress.ip_network("1.0.0.0/8").is_private)
1786+
1787+
self.assertEqual(True,ipaddress.ip_network("0.0.0.0/8").is_private)
1788+
self.assertEqual(True,ipaddress.ip_network("10.0.0.0/8").is_private)
1789+
self.assertEqual(True,ipaddress.ip_network("127.0.0.0/8").is_private)
1790+
self.assertEqual(True,ipaddress.ip_network("169.254.0.0/16").is_private)
1791+
self.assertEqual(True,ipaddress.ip_network("172.16.0.0/12").is_private)
1792+
self.assertEqual(True,ipaddress.ip_network("192.0.0.0/29").is_private)
1793+
self.assertEqual(False,ipaddress.ip_network("192.0.0.9/32").is_private)
1794+
self.assertEqual(True,ipaddress.ip_network("192.0.0.170/31").is_private)
1795+
self.assertEqual(True,ipaddress.ip_network("192.0.2.0/24").is_private)
1796+
self.assertEqual(True,ipaddress.ip_network("192.168.0.0/16").is_private)
1797+
self.assertEqual(True,ipaddress.ip_network("198.18.0.0/15").is_private)
1798+
self.assertEqual(True,ipaddress.ip_network("198.51.100.0/24").is_private)
1799+
self.assertEqual(True,ipaddress.ip_network("203.0.113.0/24").is_private)
1800+
self.assertEqual(True,ipaddress.ip_network("240.0.0.0/4").is_private)
1801+
self.assertEqual(True,ipaddress.ip_network("255.255.255.255/32").is_private)
1802+
1803+
self.assertEqual(False,ipaddress.ip_network("::/0").is_private)
1804+
self.assertEqual(False,ipaddress.ip_network("::ff/128").is_private)
1805+
1806+
self.assertEqual(True,ipaddress.ip_network("::1/128").is_private)
1807+
self.assertEqual(True,ipaddress.ip_network("::/128").is_private)
1808+
self.assertEqual(True,ipaddress.ip_network("::ffff:0:0/96").is_private)
1809+
self.assertEqual(True,ipaddress.ip_network("100::/64").is_private)
1810+
self.assertEqual(True,ipaddress.ip_network("2001:2::/48").is_private)
1811+
self.assertEqual(False,ipaddress.ip_network("2001:3::/48").is_private)
1812+
self.assertEqual(True,ipaddress.ip_network("2001:db8::/32").is_private)
1813+
self.assertEqual(True,ipaddress.ip_network("2001:10::/28").is_private)
1814+
self.assertEqual(True,ipaddress.ip_network("fc00::/7").is_private)
1815+
self.assertEqual(True,ipaddress.ip_network("fe80::/10").is_private)
1816+
17791817
deftestReservedIpv6(self):
17801818

17811819
self.assertEqual(True,ipaddress.ip_network('ffff::').is_multicast)
@@ -1849,6 +1887,20 @@ def testReservedIpv6(self):
18491887
self.assertEqual(True,ipaddress.ip_address('0::0').is_unspecified)
18501888
self.assertEqual(False,ipaddress.ip_address('::1').is_unspecified)
18511889

1890+
self.assertFalse(ipaddress.ip_address('64:ff9b:1::').is_global)
1891+
self.assertFalse(ipaddress.ip_address('2001::').is_global)
1892+
self.assertTrue(ipaddress.ip_address('2001:1::1').is_global)
1893+
self.assertTrue(ipaddress.ip_address('2001:1::2').is_global)
1894+
self.assertFalse(ipaddress.ip_address('2001:2::').is_global)
1895+
self.assertTrue(ipaddress.ip_address('2001:3::').is_global)
1896+
self.assertFalse(ipaddress.ip_address('2001:4::').is_global)
1897+
self.assertTrue(ipaddress.ip_address('2001:4:112::').is_global)
1898+
self.assertFalse(ipaddress.ip_address('2001:10::').is_global)
1899+
self.assertTrue(ipaddress.ip_address('2001:20::').is_global)
1900+
self.assertTrue(ipaddress.ip_address('2001:30::').is_global)
1901+
self.assertFalse(ipaddress.ip_address('2001:40::').is_global)
1902+
self.assertFalse(ipaddress.ip_address('2002::').is_global)
1903+
18521904
# some generic IETF reserved addresses
18531905
self.assertEqual(True,ipaddress.ip_address('100::').is_reserved)
18541906
self.assertEqual(True,ipaddress.ip_network('4000::1/128').is_reserved)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Fixed various false positives and false negatives in
2+
3+
*:attr:`ipaddress.IPv4Address.is_private` (see these docs for details)
4+
*:attr:`ipaddress.IPv4Address.is_global`
5+
*:attr:`ipaddress.IPv6Address.is_private`
6+
*:attr:`ipaddress.IPv6Address.is_global`
7+
8+
Also in the corresponding:class:`ipaddress.IPv4Network` and:class:`ipaddress.IPv6Network`
9+
attributes.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp