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

Commit40d75c2

Browse files
authored
GH-113171: Fix "private" (non-global) IP address ranges (GH-113179)
*GH-113171: Fix "private" (really non-global) IP address rangesThe _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.I left 100.64.0.0/10 alone, for now, as it's been made special in [1]and I'm not sure if we want to undo that as I don't quite understand themotivation behind it.The _address_exclude_many() call returns 8 networks for IPv4, 121networks for IPv6.[1]#61602
1 parent3be9b9d commit40d75c2

File tree

5 files changed

+82
-7
lines changed

5 files changed

+82
-7
lines changed

‎Doc/library/ipaddress.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,18 @@ write code that handles both IP versions correctly. Address objects are
192192
``is_private`` has value opposite to:attr:`is_global`, except for the shared address space
193193
(``100.64.0.0/10`` range) where they are both ``False``.
194194

195+
..versionchanged::3.13
196+
197+
Fixed some false positives and false negatives.
198+
199+
* ``192.0.0.0/24`` is considered private with the exception of ``192.0.0.9/32`` and
200+
``192.0.0.10/32`` (previously: only the ``192.0.0.0/29`` sub-range was considered private).
201+
* ``64:ff9b:1::/48`` is considered private.
202+
* ``2002::/16`` is considered private.
203+
* There are exceptions within ``2001::/23`` (otherwise considered private): ``2001:1::1/128``,
204+
``2001:1::2/128``, ``2001:3::/32``, ``2001:4:112::/48``, ``2001:20::/28``, ``2001:30::/28``.
205+
The exceptions are not considered private.
206+
195207
..attribute::is_global
196208

197209
``True`` if the address is defined as globally reachable by
@@ -209,6 +221,10 @@ write code that handles both IP versions correctly. Address objects are
209221

210222
..versionadded::3.4
211223

224+
..versionchanged::3.13
225+
226+
Fixed some false positives and false negatives, see:attr:`is_private` for details.
227+
212228
..attribute::is_unspecified
213229

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

‎Doc/whatsnew/3.13.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ ipaddress
401401

402402
* Add the:attr:`ipaddress.IPv4Address.ipv6_mapped` property, which returns the IPv4-mapped IPv6 address.
403403
(Contributed by Charles Machalow in:gh:`109466`.)
404+
* Fix ``is_global`` and ``is_private`` behavior in ``IPv4Address``, ``IPv6Address``, ``IPv4Network``
405+
and ``IPv6Network``.
404406

405407
itertools
406408
---------

‎Lib/ipaddress.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,11 @@ def is_private(self):
10861086
"""
10871087
returnany(self.network_addressinpriv_networkand
10881088
self.broadcast_addressinpriv_network
1089-
forpriv_networkinself._constants._private_networks)
1089+
forpriv_networkinself._constants._private_networks)andall(
1090+
self.network_addressnotinnetworkand
1091+
self.broadcast_addressnotinnetwork
1092+
fornetworkinself._constants._private_networks_exceptions
1093+
)
10901094

10911095
@property
10921096
defis_global(self):
@@ -1347,7 +1351,10 @@ def is_private(self):
13471351
``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10``
13481352
IPv4 range where they are both ``False``.
13491353
"""
1350-
returnany(selfinnetfornetinself._constants._private_networks)
1354+
return (
1355+
any(selfinnetfornetinself._constants._private_networks)
1356+
andall(selfnotinnetfornetinself._constants._private_networks_exceptions)
1357+
)
13511358

13521359
@property
13531360
@functools.lru_cache()
@@ -1578,13 +1585,15 @@ class _IPv4Constants:
15781585

15791586
_public_network=IPv4Network('100.64.0.0/10')
15801587

1588+
# Not globally reachable address blocks listed on
1589+
# https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
15811590
_private_networks= [
15821591
IPv4Network('0.0.0.0/8'),
15831592
IPv4Network('10.0.0.0/8'),
15841593
IPv4Network('127.0.0.0/8'),
15851594
IPv4Network('169.254.0.0/16'),
15861595
IPv4Network('172.16.0.0/12'),
1587-
IPv4Network('192.0.0.0/29'),
1596+
IPv4Network('192.0.0.0/24'),
15881597
IPv4Network('192.0.0.170/31'),
15891598
IPv4Network('192.0.2.0/24'),
15901599
IPv4Network('192.168.0.0/16'),
@@ -1595,6 +1604,11 @@ class _IPv4Constants:
15951604
IPv4Network('255.255.255.255/32'),
15961605
]
15971606

1607+
_private_networks_exceptions= [
1608+
IPv4Network('192.0.0.9/32'),
1609+
IPv4Network('192.0.0.10/32'),
1610+
]
1611+
15981612
_reserved_network=IPv4Network('240.0.0.0/4')
15991613

16001614
_unspecified_address=IPv4Address('0.0.0.0')
@@ -2086,7 +2100,10 @@ def is_private(self):
20862100
ipv4_mapped=self.ipv4_mapped
20872101
ifipv4_mappedisnotNone:
20882102
returnipv4_mapped.is_private
2089-
returnany(selfinnetfornetinself._constants._private_networks)
2103+
return (
2104+
any(selfinnetfornetinself._constants._private_networks)
2105+
andall(selfnotinnetfornetinself._constants._private_networks_exceptions)
2106+
)
20902107

20912108
@property
20922109
defis_global(self):
@@ -2342,19 +2359,31 @@ class _IPv6Constants:
23422359

23432360
_multicast_network=IPv6Network('ff00::/8')
23442361

2362+
# Not globally reachable address blocks listed on
2363+
# https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
23452364
_private_networks= [
23462365
IPv6Network('::1/128'),
23472366
IPv6Network('::/128'),
23482367
IPv6Network('::ffff:0:0/96'),
2368+
IPv6Network('64:ff9b:1::/48'),
23492369
IPv6Network('100::/64'),
23502370
IPv6Network('2001::/23'),
2351-
IPv6Network('2001:2::/48'),
23522371
IPv6Network('2001:db8::/32'),
2353-
IPv6Network('2001:10::/28'),
2372+
# IANA says N/A, let's consider it not globally reachable to be safe
2373+
IPv6Network('2002::/16'),
23542374
IPv6Network('fc00::/7'),
23552375
IPv6Network('fe80::/10'),
23562376
]
23572377

2378+
_private_networks_exceptions= [
2379+
IPv6Network('2001:1::1/128'),
2380+
IPv6Network('2001:1::2/128'),
2381+
IPv6Network('2001:3::/32'),
2382+
IPv6Network('2001:4:112::/48'),
2383+
IPv6Network('2001:20::/28'),
2384+
IPv6Network('2001:30::/28'),
2385+
]
2386+
23582387
_reserved_networks= [
23592388
IPv6Network('::/8'),IPv6Network('100::/8'),
23602389
IPv6Network('200::/7'),IPv6Network('400::/6'),

‎Lib/test/test_ipaddress.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2288,6 +2288,10 @@ def testReservedIpv4(self):
22882288
self.assertEqual(True,ipaddress.ip_address(
22892289
'172.31.255.255').is_private)
22902290
self.assertEqual(False,ipaddress.ip_address('172.32.0.0').is_private)
2291+
self.assertFalse(ipaddress.ip_address('192.0.0.0').is_global)
2292+
self.assertTrue(ipaddress.ip_address('192.0.0.9').is_global)
2293+
self.assertTrue(ipaddress.ip_address('192.0.0.10').is_global)
2294+
self.assertFalse(ipaddress.ip_address('192.0.0.255').is_global)
22912295

22922296
self.assertEqual(True,
22932297
ipaddress.ip_address('169.254.100.200').is_link_local)
@@ -2313,6 +2317,7 @@ def testPrivateNetworks(self):
23132317
self.assertEqual(True,ipaddress.ip_network("169.254.0.0/16").is_private)
23142318
self.assertEqual(True,ipaddress.ip_network("172.16.0.0/12").is_private)
23152319
self.assertEqual(True,ipaddress.ip_network("192.0.0.0/29").is_private)
2320+
self.assertEqual(False,ipaddress.ip_network("192.0.0.9/32").is_private)
23162321
self.assertEqual(True,ipaddress.ip_network("192.0.0.170/31").is_private)
23172322
self.assertEqual(True,ipaddress.ip_network("192.0.2.0/24").is_private)
23182323
self.assertEqual(True,ipaddress.ip_network("192.168.0.0/16").is_private)
@@ -2329,8 +2334,8 @@ def testPrivateNetworks(self):
23292334
self.assertEqual(True,ipaddress.ip_network("::/128").is_private)
23302335
self.assertEqual(True,ipaddress.ip_network("::ffff:0:0/96").is_private)
23312336
self.assertEqual(True,ipaddress.ip_network("100::/64").is_private)
2332-
self.assertEqual(True,ipaddress.ip_network("2001::/23").is_private)
23332337
self.assertEqual(True,ipaddress.ip_network("2001:2::/48").is_private)
2338+
self.assertEqual(False,ipaddress.ip_network("2001:3::/48").is_private)
23342339
self.assertEqual(True,ipaddress.ip_network("2001:db8::/32").is_private)
23352340
self.assertEqual(True,ipaddress.ip_network("2001:10::/28").is_private)
23362341
self.assertEqual(True,ipaddress.ip_network("fc00::/7").is_private)
@@ -2409,6 +2414,20 @@ def testReservedIpv6(self):
24092414
self.assertEqual(True,ipaddress.ip_address('0::0').is_unspecified)
24102415
self.assertEqual(False,ipaddress.ip_address('::1').is_unspecified)
24112416

2417+
self.assertFalse(ipaddress.ip_address('64:ff9b:1::').is_global)
2418+
self.assertFalse(ipaddress.ip_address('2001::').is_global)
2419+
self.assertTrue(ipaddress.ip_address('2001:1::1').is_global)
2420+
self.assertTrue(ipaddress.ip_address('2001:1::2').is_global)
2421+
self.assertFalse(ipaddress.ip_address('2001:2::').is_global)
2422+
self.assertTrue(ipaddress.ip_address('2001:3::').is_global)
2423+
self.assertFalse(ipaddress.ip_address('2001:4::').is_global)
2424+
self.assertTrue(ipaddress.ip_address('2001:4:112::').is_global)
2425+
self.assertFalse(ipaddress.ip_address('2001:10::').is_global)
2426+
self.assertTrue(ipaddress.ip_address('2001:20::').is_global)
2427+
self.assertTrue(ipaddress.ip_address('2001:30::').is_global)
2428+
self.assertFalse(ipaddress.ip_address('2001:40::').is_global)
2429+
self.assertFalse(ipaddress.ip_address('2002::').is_global)
2430+
24122431
# some generic IETF reserved addresses
24132432
self.assertEqual(True,ipaddress.ip_address('100::').is_reserved)
24142433
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