pvl.hosts-dns: support short-form --reverse-host=...
authorTero Marttila <terom@paivola.fi>
Thu, 19 Dec 2013 01:46:59 +0200
changeset 312 b814f87ed40d
parent 311 0e79917de9f7
child 313 c211ef65fd67
pvl.hosts-dns: support short-form --reverse-host=...
bin/pvl.hosts-dns
--- a/bin/pvl.hosts-dns	Thu Dec 19 01:20:33 2013 +0200
+++ b/bin/pvl.hosts-dns	Thu Dec 19 01:46:59 2013 +0200
@@ -93,6 +93,64 @@
         # preserve ordering
         yield rr
 
+def split_ipv6_parts (prefix) :
+    for hextet in prefix.rstrip(':').split(':') :
+        for nibble in hextet.rjust(4, '0') :
+            yield nibble
+
+def build_ipv6_parts (parts) :
+    for i in xrange(0, len(parts), 4) :
+        yield ''.join(parts[i:i+4])
+    
+    # suffix ::
+    if len(parts) < 32 :
+        yield ''
+        yield ''
+
+def parse_prefix (prefix) :
+    """
+        Return an ipaddr.IPNetwork from given IPv4/IPv6 prefix.
+
+        >>> parse_prefix('127.0.0.0/8')
+        IPv4Network('127.0.0.0/8')
+        >>> parse_prefix('127.')
+        IPv4Network('127.0.0.0/8')
+        >>> parse_prefix('10')
+        IPv4Network('10.0.0.0/8')
+        >>> parse_prefix('192.168')
+        IPv4Network('192.168.0.0/16')
+        >>> parse_prefix('fe80:')
+        IPv6Network('fe80::/16')
+        >>> parse_prefix('2001:db8::')
+        IPv6Network('2001:db8::/32')
+        >>> parse_prefix('2001:db8:1:2')
+        IPv6Network('2001:db8:1:2::/64')
+    """
+
+    if '/' in prefix :
+        return ipaddr.IPNetwork(prefix)
+
+    elif '.' in prefix or prefix.isdigit() :
+        parts = prefix.rstrip('.').split('.')
+        prefixlen = len(parts) * 8
+        
+        return ipaddr.IPv4Network('{prefix}/{prefixlen}'.format(
+            prefix      = '.'.join(parts + ['0' for i in xrange(4 - len(parts))]),
+            prefixlen   = prefixlen,
+        ))
+   
+    elif ':' in prefix :
+        parts = list(split_ipv6_parts(prefix))
+        prefixlen = len(parts) * 4
+
+        return ipaddr.IPv6Network('{prefix}/{prefixlen}'.format(
+            prefix      = ':'.join(build_ipv6_parts(parts)),
+            prefixlen   = prefixlen,
+        ))
+
+    else :
+        raise ValueError("Unrecognized IP prefix string: %s" % (prefix, ))
+
 def process_hosts_ips (options, hosts, prefix) :
     """
         Yield (ip, fqnd) for hosts within given prefix.
@@ -174,7 +232,7 @@
             help="Generate forward zone for domain")
 
     parser.add_option('--reverse-zone',         metavar='PREFIX',
-            help="Generate reverse zone for prefx")
+            help="Generate reverse zone for prefix")
 
     parser.add_option('--unknown-host',         metavar='NAME',
             help="Generate records for unused IPs")
@@ -193,7 +251,7 @@
     
     if options.reverse_zone :
         apply_zone(options, 
-                process_hosts_reverse(options, hosts, ipaddr.IPNetwork(options.reverse_zone)),
+                process_hosts_reverse(options, hosts, parse_prefix(options.reverse_zone)),
         )
 
 if __name__ == '__main__':