#!/usr/bin/env python
# ipv6calc 0.1
# simple utility to calculate pointer domain names for IPv6 prefixes

__author__="Damian Pasternok <my_forename at pasternok.org>"
__program__="ipv6calc"
__version__="0.1"
__date__ ="$2009-08-01 19:57:24$"

import re
import socket
import struct
import sys

class IPv6Parser:
    def __init__(self, prefix):
        self.prefix = prefix

    def parse_netmask(self):
        netmask = re.findall("\/(\d{1}|[1-9]\d|1[0-1]\d|12[0-8])$", self.prefix)
        if netmask:
            return int(netmask[0])
        else:
            return -1

    def parse_addr6(self):
        addr6 = re.findall("^(.*)/", self.prefix)
        if addr6:
            addr6 = addr6[0]
            try:
                addr6 = socket.inet_pton(socket.AF_INET6, addr6)
            except:
                return -1
            return addr6
        else:
            return -1

    def round_netmask(self, netmask):
        while 1:
            if netmask % 4:
                netmask += 1
            else:
                return netmask

class IPv6Calc(IPv6Parser):
    def __init__(self, prefix):
        IPv6Parser.__init__(self, prefix)
        if self.parse_netmask() == -1 or self.parse_addr6() == -1:
            print "Wrong prefix. Please try again..."
            help()
        else:
            self.__calculate_revdns()

    def __calculate_revdns(self):
        addr6 = self.parse_addr6()
        netmask = self.parse_netmask()
        addr6_tlist = []
        addr6_list = []
        for i in range(16): # 16 x 8 bits
            # appends one-element tupple
            addr6_tlist.append(struct.unpack("B", addr6[i])[0])
            # upper nibble
            unibble = re.findall("^0x([\da-f]{1,2})$",
                str(hex(addr6_tlist[i] >> 4)))
            # lower nibble
            lnibble = re.findall("^0x([\da-f]{1,2})$",
                str(hex(addr6_tlist[i] & 0x0f)))
            addr6_list.append(unibble[0])
            addr6_list.append(lnibble[0])
        for i in range(32 - self.round_netmask(netmask) / 4):
            addr6_list.pop()
        addr6_list.reverse()
        ipv6_rev = ""
        for i in addr6_list:
            ipv6_rev += i + "."
        ipv6_rev += "ip6.arpa."
        print ipv6_rev

def help():
    print r"""Usage: %s <ipv6_prefix>
    --version   display version

Prefix examples:
 ::ffff:192.168.0.1/128
 2001:05c0:1501:bb00::/56""" % sys.argv[0]
    return

def version():
    print r"""%s %s
Copyright (C) 2009 %s
This code is free software under the GPLv3+.""" % (__program__, __version__,
    __author__)
    return

def main():
    if len(sys.argv) == 1:
        help()
    elif sys.argv[1] == "--version":
        version()
    else:
        try:
            IPv6Calc(sys.argv[1])
        except:
            help()
    return

if __name__ == "__main__":
    main()