diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 703fa289dda1fb..d2b8960ac9e3f6 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1255,13 +1255,20 @@ def _string_from_ip_int(cls, ip_int): return '.'.join(map(str, ip_int.to_bytes(4, 'big'))) def _reverse_pointer(self): - """Return the reverse DNS pointer name for the IPv4 address. + """Return the reverse DNS pointer name for the IPv4 address or network. This implements the method described in RFC1035 3.5. """ - reverse_octets = str(self).split('.')[::-1] - return '.'.join(reverse_octets) + '.in-addr.arpa' + prefix = getattr(self, 'prefixlen', IPV4LENGTH) + octet_count, remainder = divmod(prefix, 8) # each octet is 8 bits long + if remainder: + raise NetmaskValueError( + 'Reverse pointer cannot be generated for given prefix size') + address_exploded = getattr(self, 'network_address', self).exploded + reverse_octets = address_exploded.split('.')[:octet_count][::-1] + reverse_octets.append('in-addr.arpa') + return '.'.join(reverse_octets) class IPv4Address(_BaseV4, _BaseAddress): @@ -1870,13 +1877,20 @@ def _explode_shorthand_ip_string(self): return ':'.join(parts) def _reverse_pointer(self): - """Return the reverse DNS pointer name for the IPv6 address. + """Return the reverse DNS pointer name for the IPv6 address or network. This implements the method described in RFC3596 2.5. """ - reverse_chars = self.exploded[::-1].replace(':', '') - return '.'.join(reverse_chars) + '.ip6.arpa' + prefix = getattr(self, 'prefixlen', IPV6LENGTH) + char_count, remainder = divmod(prefix, 4) # each char is 4 bits long + if remainder: + raise NetmaskValueError( + 'Reverse pointer cannot be generated for given prefix size') + address_exploded = getattr(self, 'network_address', self).exploded + reverse_chars = list(address_exploded.replace(':', '')[:char_count][::-1]) + reverse_chars.append('ip6.arpa') + return '.'.join(reverse_chars) @staticmethod def _split_scope_id(ip_str): diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index b1ac2b94f41b38..afa852bb64ef76 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -709,6 +709,24 @@ def test_subnet_of_mixed_types(self): ipaddress.IPv6Network('::1/128').subnet_of( ipaddress.IPv4Network('10.0.0.0/30')) + def test_reverse_pointer(self): + self.assertEqual(self.factory('0.0.0.0/0').reverse_pointer, + 'in-addr.arpa') + self.assertEqual(self.factory('127.0.0.0/8').reverse_pointer, + '127.in-addr.arpa') + self.assertEqual(self.factory('127.12.0.0/16').reverse_pointer, + '12.127.in-addr.arpa') + self.assertEqual(self.factory('127.12.34.0/24').reverse_pointer, + '34.12.127.in-addr.arpa') + self.assertEqual(self.factory('127.12.34.56/32').reverse_pointer, + '56.34.12.127.in-addr.arpa') + + with self.assertRaises(ipaddress.NetmaskValueError): + self.factory('127.0.0.0/12').reverse_pointer + + with self.assertRaises(ipaddress.NetmaskValueError): + self.factory('127.23.0.0/17').reverse_pointer + class NetmaskTestMixin_v6(CommonTestMixin_v6): """Input validation on interfaces and networks is very similar""" @@ -865,6 +883,24 @@ def test_supernet_of(self): self.factory('2000:aaa::/48').supernet_of( self.factory('2000:aaa::/56'))) + def test_reverse_pointer(self): + self.assertEqual(self.factory('::/0').reverse_pointer, 'ip6.arpa') + self.assertEqual(self.factory('2000::/4').reverse_pointer, '2.ip6.arpa') + self.assertEqual(self.factory('2000::/8').reverse_pointer, + '0.2.ip6.arpa') + self.assertEqual(self.factory('2001:db8::/32').reverse_pointer, + '8.b.d.0.1.0.0.2.ip6.arpa') + self.assertEqual(self.factory('2001:db8:1234:5678::/64').reverse_pointer, + '8.7.6.5.4.3.2.1.8.b.d.0.1.0.0.2.ip6.arpa') + self.assertEqual(self.factory('2001:db8::1/128').reverse_pointer, + '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.b.d.0.1.0.0.2.ip6.arpa') + + with self.assertRaises(ipaddress.NetmaskValueError): + self.factory('2000::/7').reverse_pointer + + with self.assertRaises(ipaddress.NetmaskValueError): + self.factory('2001:db8::10/127').reverse_pointer class FactoryFunctionErrors(BaseTestCase): diff --git a/Misc/NEWS.d/next/Library/2021-10-17-18-47-46.gh-issue-74713.-BnGug.rst b/Misc/NEWS.d/next/Library/2021-10-17-18-47-46.gh-issue-74713.-BnGug.rst new file mode 100644 index 00000000000000..4f872280e0842b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-10-17-18-47-46.gh-issue-74713.-BnGug.rst @@ -0,0 +1,2 @@ +Fix reverse pointer generation for :class:`ipaddress.IPv4Network` and +:class:`ipaddress.IPv6Network` objects.