Skip to content

Commit 35c5efb

Browse files
committed
gh-117566: fix IPv6Address.is_loopback for IPv4-mapped loopbacks
While properties like IPv6Address.is_private account for IPv4-mapped IPv6 addresses, such as for example: >>> ipaddress.ip_address("192.168.0.1").is_private True >>> ipaddress.ip_address("::ffff:192.168.0.1").is_private True ...the same doesn't currently apply to the is_loopback property: >>> ipaddress.ip_address("127.0.0.1").is_loopback True >>> ipaddress.ip_address("::ffff:127.0.0.1").is_loopback False At minimum, this inconsistency between different properties is counter-intuitive. Moreover, ::ffff:127.0.0.0/104 is for all intents and purposes a loopback address, and should be treated as such.
1 parent f180b31 commit 35c5efb

File tree

3 files changed

+23
-1
lines changed

3 files changed

+23
-1
lines changed

Lib/ipaddress.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,9 @@ def is_loopback(self):
21422142
RFC 2373 2.5.3.
21432143
21442144
"""
2145+
ipv4_mapped = self.ipv4_mapped
2146+
if ipv4_mapped is not None:
2147+
return ipv4_mapped.is_loopback
21452148
return self._ip == 1
21462149

21472150
@property
@@ -2258,7 +2261,7 @@ def is_unspecified(self):
22582261

22592262
@property
22602263
def is_loopback(self):
2261-
return self._ip == 1 and self.network.is_loopback
2264+
return super().is_loopback and self.network.is_loopback
22622265

22632266

22642267
class IPv6Network(_BaseV6, _BaseNetwork):

Lib/test/test_ipaddress.py

+16
Original file line numberDiff line numberDiff line change
@@ -2446,6 +2446,22 @@ def testIpv4MappedPrivateCheck(self):
24462446
self.assertEqual(
24472447
False, ipaddress.ip_address('::ffff:172.32.0.0').is_private)
24482448

2449+
def testIpv4MappedLocalCheck(self):
2450+
# test networks
2451+
self.assertEqual(True, ipaddress.ip_network(
2452+
'::ffff:127.100.200.254/128').is_loopback)
2453+
self.assertEqual(True, ipaddress.ip_network(
2454+
'::ffff:127.42.0.0/112').is_loopback)
2455+
self.assertEqual(False, ipaddress.ip_network(
2456+
'::ffff:128.0.0.0').is_loopback)
2457+
# test addresses
2458+
self.assertEqual(True, ipaddress.ip_address(
2459+
'::ffff:127.100.200.254').is_loopback)
2460+
self.assertEqual(True, ipaddress.ip_address(
2461+
'::ffff:127.42.0.0').is_loopback)
2462+
self.assertEqual(False, ipaddress.ip_address(
2463+
'::ffff:128.0.0.0').is_loopback)
2464+
24492465
def testAddrExclude(self):
24502466
addr1 = ipaddress.ip_network('10.1.1.0/24')
24512467
addr2 = ipaddress.ip_network('10.1.1.0/26')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:meth:`ipaddress.IPv6Address.is_loopback` will now return ``True`` for
2+
IPv4-mapped loopback addresses, i.e. addresses in the
3+
``::ffff:127.0.0.0/104`` address space.

0 commit comments

Comments
 (0)