#!/usr/bin/env python3
# arpaname -- convert IP addresses to their reverse-lookup domain names
#
# This is an improved version of BIND's 'arpaname' with support for CIDR
# prefixes, e.g. `arpaname 2001:db8::/48` outputs the domain for that network.

import argparse
import ipaddress
import sys

parser = argparse.ArgumentParser()
parser.add_argument("address", nargs="+")
args = parser.parse_args()

for arg in args.address:
    if "/" in arg:
        net = ipaddress.ip_network(arg)
        rev = net.reverse_pointer.split(".")
        if net.version == 6:
            nibbles, extrabits = divmod(net.prefixlen, 4)
            # IPv6Network.reverse_pointer returns the "/nn" as individual
            # nibbles ["n", "n", "/"]. Discard it (i.e. keep only the number
            # of nibbles we need, plus two for .ip6.arpa)
            if extrabits != 0:
                rev = rev[-(nibbles+3):]
                start = int(rev[0], 16)
                count = 2 ** (4 - extrabits)
                for i in range(count):
                    rev[0] = "%x" % (start + i)
                    print(".".join(rev))
            else:
                rev = rev[-(nibbles+2):]
                print(".".join(rev))
        else:
            octets, extrabits = divmod(net.prefixlen, 8)
            # IPv4Network.reverse_pointer returns the whole "xy/nn" as the
            # leftmost octet. For /32 we should trim it off; for sub-/24 cases
            # use a dash as the RFC begrudgingly recommends; in other cases
            # discard it.
            if net.prefixlen == 32:
                rev[0] = rev[0].split("/")[0]
                print(".".join(rev))
            elif net.prefixlen > 24:
                # print a sub-/24 delegation in RFC 2317 style
                print("arpaname: using RFC 2317 style sub-/24 delegation",
                      file=sys.stderr)
                rev[0] = rev[0].replace("/", "-")
                print(".".join(rev))
            elif extrabits != 0:
                rev = rev[-(octets+3):]
                start = int(rev[0], 10)
                count = 2 ** (8 - extrabits)
                for i in range(count):
                    rev[0] = "%d" % (start + i)
                    print(".".join(rev))
            else:
                rev = rev[-(octets+2):]
                print(".".join(rev))
    else:
        net = ipaddress.ip_address(arg)
        print(net.reverse_pointer)
