diff -r 560ba0544254 -r 713d0495288e bin/pvl.hosts-dns --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/pvl.hosts-dns Mon Dec 16 18:37:08 2013 +0200 @@ -0,0 +1,129 @@ +#!/usr/bin/env python + + +import pvl.args +import pvl.dns.zone + +import configobj +import ipaddr +import logging; log = logging.getLogger('pvl.hosts-dns') +import math +import optparse + +def apply_hosts_file (options, file) : + """ + Load hosts from a file. + """ + config = configobj.ConfigObj(file, + encoding = options.hosts_charset, + ) + + for host in config.sections : + yield host, config[host] + +def apply_hosts (options, args) : + """ + Load hosts from arguments. + """ + + for file in pvl.args.apply_files(args, 'r') : + for host in apply_hosts_file(options, file) : + yield host + +def process_hosts_forward (options, hosts) : + for host, fields in hosts : + domain = fields.get('domain', options.hosts_domain) + + if options.forward_zone and domain != options.forward_zone : + continue + + ip = fields.get('ip') + + if ip : + yield pvl.dns.zone.ZoneRecord.A(host, value) + + # aliases + for field, value in fields.iteritems() : + if field.startswith('alias.') : + yield pvl.dns.zone.ZoneRecord.CNAME(value, host) + +def apply_reverse_zone (options, prefix, address) : + """ + Determine the correct reverse-dns name for the given address with the reverse zone for the given prefix. + """ + + assert prefix.version == address.version + + hostbits = prefix.max_prefixlen - prefix.prefixlen + + if prefix.version == 4 : + labelbytes = int(math.ceil(hostbits / 8.0)) + labelraw = address.packed[-labelbytes:] + + return '.'.join(reversed([str(ord(x)) for x in labelraw])) + else : + raise ValueError("unsupported address version: %s" % (prefix, )) + +def process_hosts_reverse (options, hosts) : + for host, fields in hosts : + domain = fields.get('domain', options.hosts_domain) + ip = fields.get('ip') + + if ip : + ip = ipaddr.IPAddress(ip) + + if not ip or ip not in options.reverse_zone : + continue + + # reverse against the prefix origin + ptr = apply_reverse_zone(options, options.reverse_zone, ip) + + yield pvl.dns.zone.ZoneRecord.PTR(ptr, pvl.dns.zone.fqdn(host, domain)) + +def main (argv) : + """ + Generate bind zonefiles from host definitions. + """ + + parser = optparse.OptionParser(main.__doc__) + parser.add_option_group(pvl.args.parser(parser)) + + hosts = optparse.OptionGroup(parser, "Hosts input") + hosts.add_option('--hosts-charset', metavar='CHARSET', default='utf-8', + help="Encoding used for host files") + + hosts.add_option('--hosts-domain', metavar='DOMAIN', + help="Default domain for hosts") + + parser.add_option_group(hosts) + + parser.add_option('--forward-zone', metavar='DOMAIN', + help="Generate forward zone for domain") + + parser.add_option('--reverse-zone', metavar='PREFIX', + help="Generate reverse zone for prefx") + + options, args = parser.parse_args(argv[1:]) + pvl.args.apply(options) + + # input + hosts = list(apply_hosts(options, args)) + + + if options.forward_zone : + zone = process_hosts_forward(options, hosts) + + elif options.reverse_zone : + options.reverse_zone = ipaddr.IPNetwork(options.reverse_zone) + + zone = process_hosts_reverse(options, hosts) + + else : + log.error("nothing to do") + return 1 + + for record in zone : + print unicode(record) + +if __name__ == '__main__': + pvl.args.main(main)