process-zone: support AAAA/ip6.arpa for --reverse-zone, as well as implicit record names
--- 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