Skip to content

Commit 3989894

Browse files
[3.12] gh-117566: fix IPv6Address.is_loopback for IPv4-mapped loopbacks (GH-117567) (GH-118391)
gh-117566: fix IPv6Address.is_loopback for IPv4-mapped loopbacks (GH-117567) 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. (cherry picked from commit fb7f79b) Co-authored-by: Faidon Liambotis <[email protected]>
1 parent 817190c commit 3989894

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
@@ -2100,6 +2100,9 @@ def is_loopback(self):
21002100
RFC 2373 2.5.3.
21012101
21022102
"""
2103+
ipv4_mapped = self.ipv4_mapped
2104+
if ipv4_mapped is not None:
2105+
return ipv4_mapped.is_loopback
21032106
return self._ip == 1
21042107

21052108
@property
@@ -2216,7 +2219,7 @@ def is_unspecified(self):
22162219

22172220
@property
22182221
def is_loopback(self):
2219-
return self._ip == 1 and self.network.is_loopback
2222+
return super().is_loopback and self.network.is_loopback
22202223

22212224

22222225
class IPv6Network(_BaseV6, _BaseNetwork):

Lib/test/test_ipaddress.py

+16
Original file line numberDiff line numberDiff line change
@@ -2427,6 +2427,22 @@ def testIpv4MappedPrivateCheck(self):
24272427
self.assertEqual(
24282428
False, ipaddress.ip_address('::ffff:172.32.0.0').is_private)
24292429

2430+
def testIpv4MappedLoopbackCheck(self):
2431+
# test networks
2432+
self.assertEqual(True, ipaddress.ip_network(
2433+
'::ffff:127.100.200.254/128').is_loopback)
2434+
self.assertEqual(True, ipaddress.ip_network(
2435+
'::ffff:127.42.0.0/112').is_loopback)
2436+
self.assertEqual(False, ipaddress.ip_network(
2437+
'::ffff:128.0.0.0').is_loopback)
2438+
# test addresses
2439+
self.assertEqual(True, ipaddress.ip_address(
2440+
'::ffff:127.100.200.254').is_loopback)
2441+
self.assertEqual(True, ipaddress.ip_address(
2442+
'::ffff:127.42.0.0').is_loopback)
2443+
self.assertEqual(False, ipaddress.ip_address(
2444+
'::ffff:128.0.0.0').is_loopback)
2445+
24302446
def testAddrExclude(self):
24312447
addr1 = ipaddress.ip_network('10.1.1.0/24')
24322448
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)