Skip to content

Commit ac85b8e

Browse files
picnixzmiss-islington
authored andcommitted
gh-123409: fix IPv6Address.reverse_pointer for IPv4-mapped addresses (GH-123419)
Fix functionality that was broken with better textual representation for IPv4-mapped addresses (gh-87799) (cherry picked from commit 77a2fb4) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent 65f2e24 commit ac85b8e

File tree

3 files changed

+53
-12
lines changed

3 files changed

+53
-12
lines changed

Lib/ipaddress.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,12 +1944,21 @@ def __init__(self, address):
19441944
def _explode_shorthand_ip_string(self):
19451945
ipv4_mapped = self.ipv4_mapped
19461946
if ipv4_mapped is None:
1947-
long_form = super()._explode_shorthand_ip_string()
1948-
else:
1949-
prefix_len = 30
1950-
raw_exploded_str = super()._explode_shorthand_ip_string()
1951-
long_form = "%s%s" % (raw_exploded_str[:prefix_len], str(ipv4_mapped))
1952-
return long_form
1947+
return super()._explode_shorthand_ip_string()
1948+
prefix_len = 30
1949+
raw_exploded_str = super()._explode_shorthand_ip_string()
1950+
return f"{raw_exploded_str[:prefix_len]}{ipv4_mapped!s}"
1951+
1952+
def _reverse_pointer(self):
1953+
ipv4_mapped = self.ipv4_mapped
1954+
if ipv4_mapped is None:
1955+
return super()._reverse_pointer()
1956+
prefix_len = 30
1957+
raw_exploded_str = super()._explode_shorthand_ip_string()[:prefix_len]
1958+
# ipv4 encoded using hexadecimal nibbles instead of decimals
1959+
ipv4_int = ipv4_mapped._ip
1960+
reverse_chars = f"{raw_exploded_str}{ipv4_int:008x}"[::-1].replace(':', '')
1961+
return '.'.join(reverse_chars) + '.ip6.arpa'
19531962

19541963
def _ipv4_mapped_ipv6_to_str(self):
19551964
"""Return convenient text representation of IPv4-mapped IPv6 address

Lib/test/test_ipaddress.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,12 +2579,42 @@ def testExplodeShortHandIpStr(self):
25792579
self.assertEqual('192.168.178.1', addr4.exploded)
25802580

25812581
def testReversePointer(self):
2582-
addr1 = ipaddress.IPv4Address('127.0.0.1')
2583-
addr2 = ipaddress.IPv6Address('2001:db8::1')
2584-
self.assertEqual('1.0.0.127.in-addr.arpa', addr1.reverse_pointer)
2585-
self.assertEqual('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.' +
2586-
'b.d.0.1.0.0.2.ip6.arpa',
2587-
addr2.reverse_pointer)
2582+
for addr_v4, expected in [
2583+
('127.0.0.1', '1.0.0.127.in-addr.arpa'),
2584+
# test vector: https://www.rfc-editor.org/rfc/rfc1035, §3.5
2585+
('10.2.0.52', '52.0.2.10.in-addr.arpa'),
2586+
]:
2587+
with self.subTest('ipv4_reverse_pointer', addr=addr_v4):
2588+
addr = ipaddress.IPv4Address(addr_v4)
2589+
self.assertEqual(addr.reverse_pointer, expected)
2590+
2591+
for addr_v6, expected in [
2592+
(
2593+
'2001:db8::1', (
2594+
'1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.'
2595+
'0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.'
2596+
'ip6.arpa'
2597+
)
2598+
),
2599+
(
2600+
'::FFFF:192.168.1.35', (
2601+
'3.2.1.0.8.a.0.c.f.f.f.f.0.0.0.0.'
2602+
'0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.'
2603+
'ip6.arpa'
2604+
)
2605+
),
2606+
# test vector: https://www.rfc-editor.org/rfc/rfc3596, §2.5
2607+
(
2608+
'4321:0:1:2:3:4:567:89ab', (
2609+
'b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.'
2610+
'2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.'
2611+
'ip6.arpa'
2612+
)
2613+
)
2614+
]:
2615+
with self.subTest('ipv6_reverse_pointer', addr=addr_v6):
2616+
addr = ipaddress.IPv6Address(addr_v6)
2617+
self.assertEqual(addr.reverse_pointer, expected)
25882618

25892619
def testIntRepresentation(self):
25902620
self.assertEqual(16909060, int(self.ipv4_address))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :attr:`ipaddress.IPv6Address.reverse_pointer` output according to
2+
:rfc:`RFC 3596, §2.5 <3596#section-2.5>`. Patch by Bénédikt Tran.

0 commit comments

Comments
 (0)