bin/pvl.hosts-dns
author Tero Marttila <terom@paivola.fi>
Mon, 16 Dec 2013 20:21:30 +0200
changeset 278 2db1a5323f92
parent 273 c8deaa9a2746
child 283 951e4b70bad4
permissions -rwxr-xr-x
pvl.hosts-dns: do not enumerate the entire prefix space unless using --unknown-host
#!/usr/bin/env python

import pvl.args
import pvl.hosts
import pvl.dns.zone

import ipaddr
import logging; log = logging.getLogger('pvl.hosts-dns')
import optparse

def process_hosts_names (options, hosts, domain) :
    """
        Yield ZoneRecords for the given domain's hosts.
    """

    for host in hosts :
        if options.forward_zone and host.domain != domain :
            continue
        
        if host.ip :
            yield pvl.dns.zone.ZoneRecord.A(host, host.ip)
        
        for alias in host.alias :
            yield pvl.dns.zone.ZoneRecord.CNAME(alias, host)

def process_hosts_forward (options, hosts, domain) :
    """
        Generate DNS ZoneRecords for the given domain's zone for hosts.
    """

    by_name = dict()

    for rr in process_hosts_names(options, hosts, domain) :
        if rr.name in by_name :
            raise ValueError("%s: duplicate name: %s: %s" % (rr.name, rr, by_name[rr.name]))
        else :
            by_name[rr.name] = rr
        
        # preserve ordering
        yield rr

def process_hosts_ips (options, hosts, prefix) :
    """
        Yield (ip, fqnd) for hosts within given prefix.
    """

    for host in hosts :
        if not host.ip :
            continue

        if host.ip not in prefix :
            continue

        yield host.ip, pvl.dns.zone.fqdn(host, host.domain)
 
def process_hosts_reverse (options, hosts, prefix) :
    """
        Generate DNS ZoneRecords within the given prefix's reverse-dns zone for hosts.
    """
    
    # collect data for records
    by_ip = dict()
    for ip, fqdn in process_hosts_ips(options, hosts, prefix) :
        if ip in by_ip :
            raise ValueError("%s: duplicate ip: %s: %s" % (fqdn, ip, by_ip[ip]))
        else :
            by_ip[ip] = fqdn

    if options.unknown_host :
        # enumerate all of them
        iter_ips = prefix.iterhosts()
    else :
        iter_ips = sorted(by_ip)

    for ip in iter_ips :
        if ip in by_ip :
            fqdn = by_ip[ip]
        elif options.unknown_host :
            fqdn = pvl.dns.zone.fqdn(options.unknown_host, options.hosts_domain)
        else :
            fqdn = None
        
        if fqdn :
            # reverse against the reverse-dns zone origin
            yield pvl.dns.zone.ZoneRecord.PTR(pvl.dns.zone.reverse_label(prefix, ip), fqdn)

def apply_zone (options, zone) :
    """
        Output given ZoneRecord's
    """

    for record in zone :
        print unicode(record)

def main (argv) :
    """
        Generate bind zonefiles from host definitions.
    """

    parser = optparse.OptionParser(main.__doc__)
    parser.add_option_group(pvl.args.parser(parser))
    parser.add_option_group(pvl.hosts.optparser(parser))

    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")

    parser.add_option('--unknown-host',         metavar='NAME',
            help="Generate records for unused IPs")

    options, args = parser.parse_args(argv[1:])
    pvl.args.apply(options)

    # input
    hosts = pvl.hosts.apply(options, args)

    # process
    if options.forward_zone :
        apply_zone(options, 
                process_hosts_forward(options, hosts, options.forward_zone),
        )
    
    if options.reverse_zone :
        apply_zone(options, 
                process_hosts_reverse(options, hosts, ipaddr.IPNetwork(options.reverse_zone)),
        )

if __name__ == '__main__':
    pvl.args.main(main)