process-zone: support AAAA/ip6.arpa for --reverse-zone, as well as implicit record names
authorTero Marttila <terom@paivola.fi>
Fri, 10 May 2013 00:05:25 +0300
changeset 603 b58236f9ea7b
parent 602 87c5570a205f
child 604 9a23fca9167a
child 620 bfdf1633b2a1
process-zone: support AAAA/ip6.arpa for --reverse-zone, as well as implicit record names
bin/process-zone
bin/update
--- a/bin/process-zone	Thu May 09 23:39:02 2013 +0300
+++ b/bin/process-zone	Fri May 10 00:05:25 2013 +0300
@@ -11,6 +11,8 @@
 from datetime import datetime
 import logging
 
+import ipaddr
+
 log = logging.getLogger('main')
 
 # command-line options, global state
@@ -83,7 +85,7 @@
             help="Domain to use for hosts in reverse zone")
 
     parser.add_option('--reverse-zone',         metavar='NET',
-            help="Generate forward zone for given subnet (x.z.y)")
+            help="Generate forward zone for given subnet (x.z.y | a:b:c:d)")
 
     # 
     parser.add_option('--doctest',              action='store_true',
@@ -244,7 +246,7 @@
             # skip
             return
         
-        # indented lines don't have name
+        # XXX: indented lines keep name from previous record
         if line.indent :
             name = None
 
@@ -645,11 +647,11 @@
             if timestamp :
                 yield TXTRecord(r.name, timestamp.strftime(TIMESTAMP_FORMAT), ttl=r.ttl)
      
-def reverse_addr (ip) :
+def reverse_ipv4 (ip) :
     """
-        Return in-addr.arpa reverse for given IPv4 IP.
+        Return in-addr.arpa reverse for given IPv4 prefix.
     """
-    
+
     # parse
     octets = tuple(int(part) for part in ip.split('.'))
 
@@ -658,6 +660,17 @@
 
     return '.'.join([str(octet) for octet in reversed(octets)] + ['in-addr', 'arpa'])
 
+def reverse_ipv6 (ip6) :
+    """
+        Return ip6.arpa reverse for given IPv6 prefix.
+    """
+
+    parts = [int(part, 16) for part in ip6.split(':')]
+    parts = ['{0:04x}'.format(part) for part in parts]
+    parts = ''.join(parts)
+
+    return '.'.join(tuple(reversed(parts)) + ( 'ip6', 'arpa'))
+
 def fqdn (*parts) :
     fqdn = '.'.join(parts)
     
@@ -672,28 +685,37 @@
         Process zone data -> reverse zone data.
     """
 
+    name = None
+
     for r in zone :
-        if r.type != 'A' :
+        # keep name from previous..
+        if r.name :
+            name = r.name
+
+        if r.type == 'A' :
+            ip, = r.data
+            ptr = reverse_ipv4(ip)
+
+        elif r.type == 'AAAA' :
+            ip, = r.data
+            ptr = reverse_ipv6(ip)
+            
+        else :
             continue
 
-        ip, = r.data
-
-        # generate reverse-addr
-        reverse = reverse_addr(ip)
-
         # verify
-        if zone and reverse.endswith(origin) :
-            reverse = reverse[:-(len(origin) + 1)]
+        if zone and ptr.endswith(origin) :
+            ptr = ptr[:-(len(origin) + 1)]
 
         else :
-            log.warning("Reverse does not match zone origin, skipping: (%s) -> %s <-> %s", ip, reverse, origin)
+            log.warning("Reverse does not match zone origin, skipping: (%s) -> %s <-> %s", ip, ptr, origin)
             continue
 
         # domain to use
         host_domain = r.origin or domain
-        host_fqdn = fqdn(r.name, host_domain)
+        host_fqdn = fqdn(name, host_domain)
 
-        yield ZoneRecord(reverse, 'PTR', [host_fqdn])
+        yield ZoneRecord(ptr, 'PTR', [host_fqdn])
 
 def write_zone_records (file, zone) :
     for r in zone :
@@ -777,7 +799,14 @@
         zone = list(process_zone_meta(zone, ignore=set(options.meta_ignore)))
 
     elif options.reverse_zone :
-        origin = reverse_addr(options.reverse_zone)
+        if ':' in options.reverse_zone :
+            # IPv6
+            origin = reverse_ipv6(options.reverse_zone)
+
+        else :
+            # IPv4
+            origin = reverse_ipv4(options.reverse_zone)
+
         domain = options.reverse_domain
 
         if not domain :
--- a/bin/update	Thu May 09 23:39:02 2013 +0300
+++ b/bin/update	Fri May 10 00:05:25 2013 +0300
@@ -123,6 +123,7 @@
         
         update_hosts        $ZONES/hosts/10                 $DATA/pvl.txt       --reverse-zone 10 --reverse-domain pvl -q
         update_hosts        $ZONES/hosts/10.0               $DATA/test.pvl.txt 	--reverse-zone 10.0 --reverse-domain test.pvl -q
+        update_hosts        $ZONES/hosts/fdc4:4cef:395a     $DATA/test.pvl.txt 	--reverse-zone fdc4:4cef:395a --reverse-domain test.pvl -q
         update_hosts        $ZONES/hosts/192.168            $DATA/pvl.txt       --reverse-zone 192.168 --reverse-domain pvl -q
 
         # XXX: unsupported --forward-zone with pvl.txt