Beispiel #1
0
    def _get_reverse_data(self, start, stop):
        for row in IPNumber.IPNumber(db).list(start=start, stop=stop):
            self.ip_numbers[int(row['ip_number_id'])] = row

        for row in ARecord.ARecord(db).list_ext(start=start, stop=stop):
            self.a_records.setdefault(int(row['ip_number_id']), []).append(row)

        for row in IPNumber.IPNumber(db).list_override(start=start, stop=stop):
            self.override_ip.setdefault(int(row['ip_number_id']),
                                        []).append(row)
        logger.debug("_get_reverse_data -> %i, %i, %i", len(self.ip_numbers),
                     len(self.a_records), len(self.override_ip))
Beispiel #2
0
    def check_reserved_addresses_in_use(self):
        """TODO: DOC

        """
        # Need to import Utils here, since Utils imports this module,
        # and we cannot have circular module dependencies.
        from Cerebrum.modules.dns.Utils import Find
        default_zone = self.const.DnsZone(getattr(cereconf, 'DNS_DEFAULT_ZONE', 'uio'))
        find = Find(self._db, default_zone)

        ip_number = IPNumber.IPNumber(self._db)
        ip_number.clear()

        res_adr_in_use = []

        for row in ip_number.find_in_range(self.ip_min, self.ip_max):
            current_address = long(row['ipnr'])
            if current_address in self.reserved_adr:
                res_adr_in_use.append(IPCalc.long_to_ip(current_address))

        if res_adr_in_use:
            res_adr_in_use.sort()
            raise SubnetError(
                "The following reserved ip's are already in use " +
                "on (new?) subnet %s/%s: " % (self.subnet_ip, self.subnet_mask) +
                "'%s'." % (', '.join(res_adr_in_use)))
def get_data_from_DB():
    """Retrieves all relevant data needed from database

    @rtype: dict
    @return: A dictionary where the keys are MAC-addresses and the
             values are lists of IP-addresses associated with each
             MAC-address.
    """
    ips_by_mac = {}

    ipnumber = IPNumber.IPNumber(db)
    all_ips = (x for x in ipnumber.list() if x['mac_adr'] is not None)
    mac_ips = 0

    for ip in all_ips:
        current = ips_by_mac.get(ip['mac_adr'], [])
        current.append(ip['a_ip'])
        ips_by_mac[ip['mac_adr']] = current
        mac_ips += 1

    ipnumber = IPv6Number.IPv6Number(db)
    all_ips = (x for x in ipnumber.list() if x['mac_adr'] is not None)

    for ip in all_ips:
        current = ips_by_mac.get(ip['mac_adr'], [])
        current.append(ip['aaaa_ip'])
        ips_by_mac[ip['mac_adr']] = current
        mac_ips += 1

    logger.info("Found a total of %s MAC-addesses in DB",
                len(ips_by_mac.keys()))
    logger.info("Found a total of %s associated IP-addesses in DB", mac_ips)
    return ips_by_mac
Beispiel #4
0
    def remove_reverse_override(self, ip_number_id, dest_host):
        """Remove reverse-map override for ip_number_id.  Will remove
        dns_owner and ip_number entries if they are no longer in
        use."""

        try:
            ipnumber = IPv6Number.IPv6Number(self._db)
            ipnumber.find(ip_number_id)
            a_type = dns.AAAA_RECORD
            ip_type = dns.IPv6_NUMBER
            o_ip_type = dns.IP_NUMBER
            o_ipnumber = IPNumber.IPNumber(self._db)
        except Errors.NotFoundError:
            ipnumber = IPNumber.IPNumber(self._db)
            ipnumber.find(ip_number_id)
            a_type = dns.A_RECORD
            ip_type = dns.IP_NUMBER
            o_ip_type = dns.IPv6_NUMBER
            o_ipnumber = IPv6Number.IPv6Number(self._db)

        ipnumber.delete_reverse_override(ip_number_id, dest_host)

        refs = self._find.find_referers(ip_number_id=ip_number_id,
                                        ip_type=ip_type)
        if not (dns.REV_IP_NUMBER in refs or a_type in refs):
            # IP no longer used
            ipnumber.delete()

        if dest_host is not None:
            refs = self._find.find_referers(dns_owner_id=dest_host,
                                            ip_type=ip_type)
            refs += self._find.find_referers(dns_owner_id=dest_host,
                                             ip_type=o_ip_type)
            if not refs:
                tmp = []
                for row in ipnumber.list_override(dns_owner_id=dest_host):
                    # One might argue that find_referers also should find
                    # this type of refs.
                    tmp.append((dns.DNS_OWNER, row['dns_owner_id']))
                for row in o_ipnumber.list_override(dns_owner_id=dest_host):
                    tmp.append((dns.DNS_OWNER, row['dns_owner_id']))

                if not tmp:
                    dns_owner = DnsOwner.DnsOwner(self._db)
                    dns_owner.find(dest_host)
                    dns_owner.delete()
Beispiel #5
0
 def __init__(self, db, default_zone):
     self._db = db
     self._arecord = ARecord.ARecord(self._db)
     self._ip_number = IPNumber.IPNumber(self._db)
     self._dns_owner = DnsOwner.DnsOwner(self._db)
     self._mx_set = DnsOwner.MXSet(self._db)
     self._host = HostInfo.HostInfo(self._db)
     self._cname = CNameRecord.CNameRecord(self._db)
     self._default_zone = default_zone
Beispiel #6
0
    def add_reverse_override(self, ip_number_id, dest_host):
        # TODO: Only allow one None/ip
        try:
            ipnumber = IPv6Number.IPv6Number(self._db)
            ipnumber.find(ip_number_id)
        except Errors.NotFoundError:
            ipnumber = IPNumber.IPNumber(self._db)

        ipnumber.add_reverse_override(ip_number_id, dest_host)
Beispiel #7
0
    def remove_arecord(self, a_record_id, try_dns_remove=False):
        """Remove an a-record identified by a_record_id.

        Will also update override_revmap and remove the entry in ip_number if
        it is no longer referred to by other tables.

        :param int a_record_id: The ARecords id.
        :param bool try_dns_remove: Remove the DNSOwner too.
        """
        ip_type = dns.IP_NUMBER
        record_type = dns.A_RECORD
        arecord = ARecord.ARecord(self._db)

        try:
            arecord.find(a_record_id)
            ip_number_id = arecord.ip_number_id
            ipnumber = IPNumber.IPNumber(self._db)
        except Errors.NotFoundError:
            arecord = AAAARecord.AAAARecord(self._db)
            arecord.find(a_record_id)
            ip_type = dns.IPv6_NUMBER
            record_type = dns.AAAA_RECORD
            ip_number_id = arecord.ipv6_number_id
            ipnumber = IPv6Number.IPv6Number(self._db)

        ipnumber.find(ip_number_id)

        dns_owner_id = arecord.dns_owner_id
        arecord._delete()

        refs = self._find.find_referers(ip_number_id=ipnumber.entity_id,
                                        ip_type=ip_type)
        if dns.REV_IP_NUMBER in refs:
            self._update_override(ipnumber.entity_id, dns_owner_id)
            refs = self._find.find_referers(ip_number_id=ipnumber.entity_id,
                                            ip_type=ip_type)

        if not (dns.REV_IP_NUMBER in refs or record_type in refs):
            # IP no longer used
            ipnumber.delete()

        # Assert that any cname/srv targets still point to atleast one
        # a-record.  Assert that host_info has atleast one associated
        # a_record.
        # TODO: This check should be somewhere that makes it is easier
        # to always enforce this constraint.
        refs = set(self._find.find_referers(dns_owner_id=dns_owner_id,
                                            ip_type=dns.IP_NUMBER))
        refs.update(self._find.find_referers(dns_owner_id=dns_owner_id,
                                             ip_type=dns.IPv6_NUMBER))
        if not any(r_type in refs
                   for r_type in (dns.A_RECORD, dns.AAAA_RECORD)):
            if dns.SRV_TARGET in refs or dns.CNAME_TARGET in refs:
                raise DNSError("Host is used as target for CNAME or SRV")

        if try_dns_remove:
            self.remove_dns_owner(dns_owner_id)
Beispiel #8
0
 def __init__(self, db, default_zone):
     self._db = db
     self._ip_number = IPNumber.IPNumber(db)
     self._ipv6_number = IPv6Number.IPv6Number(db)
     self._arecord = ARecord.ARecord(db)
     self._aaaarecord = AAAARecord.AAAARecord(db)
     self._dns_owner = DnsOwner.DnsOwner(db)
     self._mx_set = DnsOwner.MXSet(db)
     self._host = HostInfo.HostInfo(db)
     self._cname = CNameRecord.CNameRecord(db)
     self._dns_parser = DnsParser(db, default_zone)
Beispiel #9
0
    def _find_available_ip(self, subnet, no_of_addrs=None, search_start=0):
        """Returns all ips that are not reserved or taken on the given
        subnet in ascending order."""
        try:
            sub = Subnet.Subnet(self._db)
            sub.find(subnet)
            ip_number = IPNumber.IPNumber(self._db)
            ip_key = 'ip_number_id'
            ipnr = lambda x: x['ipnr']
            start = sub.ip_min
        except SubnetError:
            sub = IPv6Subnet.IPv6Subnet(self._db)
            sub.find(subnet)
            ip_number = IPv6Number.IPv6Number(self._db)
            ip_key = 'ipv6_number_id'
            ipnr = lambda x: IPv6Calc.ip_to_long(x['aaaa_ip'])
            # We'll do this, since we don't want bofh to be stuck forever
            # trying to fetch all IPv6-addresses.
            # This is ugly, but it's not only-only.
            if no_of_addrs is None:
                no_of_addrs = 100
            # A special case for IPv6 subnets, is that we'll want to be able
            # to start allocating addresses a given place in the subnet,
            # without using the reserved-addresses-functionality.
            if search_start >= sub.ip_min:
                start = search_start
            else:
                start = (sub.ip_min +
                         cereconf.DEFAULT_IPv6_SUBNET_ALLOCATION_START +
                         search_start)
        try:
            taken = {}
            for row in ip_number.find_in_range(start, sub.ip_max):
                taken[long(ipnr(row))] = int(row[ip_key])

            stop = sub.ip_max - start + 1
            n = 0
            ret = []
            while n < stop:
                if no_of_addrs is not None and len(ret) == no_of_addrs:
                    break
                if (
                        long(start+n) not in taken and
                        n+start not in sub.reserved_adr
                ):
                    ret.append(n+start)
                n += 1
            return ret
        except SubnetError:
            # Unable to find subnet; therefore, no available ips to report
            return []
Beispiel #10
0
    def find_overrides(self, dns_owner_id, only_type=False):
        """
        """
        ret = []
        ip = IPNumber.IPNumber(self._db)
        for row in ip.list_override(dns_owner_id=dns_owner_id):
            ret.append((dns.IP_NUMBER, row['ip_number_id'],))
        ip = IPv6Number.IPv6Number(self._db)
        for row in ip.list_override(dns_owner_id=dns_owner_id):
            ret.append((dns.IPv6_NUMBER, row['ipv6_number_id'],))

        if only_type:
            return [x[0] for x in ret]
        return ret
Beispiel #11
0
    def count_used_ips(self, subnet):
        """Returns the number of used ips on the given subnet.

        Returns a long.

        """

        if '.' in subnet:
            ip_number = IPNumber.IPNumber(self._db)
            sub = Subnet.Subnet(self._db)
        else:
            ip_number = IPv6Number.IPv6Number(self._db)
            sub = IPv6Subnet.IPv6Subnet(self._db)
        sub.find(subnet)
        return ip_number.count_in_range(sub.ip_min, sub.ip_max)
Beispiel #12
0
    def _populate_dnsowner(self, hostname):
        """Create or update a DnsOwner connected to the given project.

        The DnsOwner is given a trait, to affiliate it with this project-OU.

        This should rather be put in the DNS module, but due to its complexity,
        its weird layout, and my lack of IQ points to understand it, I started
        just using its API instead.

        :param str hostname: The given *FQDN* for the host.

        :rtype: DnsOwner object
        :return:
            The DnsOwner object that is created or updated.
        """
        dns_owner = DnsOwner.DnsOwner(self._db)
        dnsfind = Utils.Find(self._db, cereconf.DNS_DEFAULT_ZONE)
        ipv6number = IPv6Number.IPv6Number(self._db)
        aaaarecord = AAAARecord.AAAARecord(self._db)
        ipnumber = IPNumber.IPNumber(self._db)
        arecord = ARecord.ARecord(self._db)

        try:
            dns_owner.find_by_name(hostname)
        except Errors.NotFoundError:
            # TODO: create owner here?
            dns_owner.populate(self.const.DnsZone(cereconf.DNS_DEFAULT_ZONE),
                               hostname)
            dns_owner.write_db()
        # Affiliate with project:
        dns_owner.populate_trait(self.const.trait_project_host,
                                 target_id=self.entity_id)
        dns_owner.write_db()
        for (subnets, ipnum, record, ipstr) in (
                (self.ipv6_subnets, ipv6number, aaaarecord, "IPv6"),
                (self.ipv4_subnets, ipnumber, arecord, "IPv4")):
            # TODO: check if dnsowner already has an ip address.
            try:
                ip = dnsfind.find_free_ip(subnets.next(), no_of_addrs=1)[0]
            except StopIteration:
                raise Errors.NotFoundError("No %s-subnet for project %s" %
                                           (ipstr, self.get_project_id()))
            ipnum.populate(ip)
            ipnum.write_db()
            record.populate(dns_owner.entity_id, ipnum.entity_id)
            record.write_db()
        return dns_owner
Beispiel #13
0
 def __init__(self, db, logger, default_zone):
     self.logger = logger
     self.db = db
     self.const = Factory.get('Constants')(self.db)
     # TBD: This pre-allocating may interfere with multi-threaded bofhd
     self._arecord = ARecord.ARecord(self.db)
     self._aaaarecord = AAAARecord.AAAARecord(self.db)
     self._host = HostInfo.HostInfo(self.db)
     self._dns_owner = DnsOwner.DnsOwner(self.db)
     self._ip_number = IPNumber.IPNumber(self.db)
     self._ipv6_number = IPv6Number.IPv6Number(self.db)
     self._cname = CNameRecord.CNameRecord(self.db)
     self._validator = IntegrityHelper.Validator(self.db, default_zone)
     self._update_helper = IntegrityHelper.Updater(self.db)
     self._mx_set = DnsOwner.MXSet(self.db)
     self.default_zone = default_zone
     self._find = Utils.Find(self.db, default_zone)
     self._parser = Utils.DnsParser(self.db, default_zone)
Beispiel #14
0
    def check_reserved_addresses_in_use(self):
        """TODO: DOC

        """
        ip_number = IPNumber.IPNumber(self._db)
        ip_number.clear()

        res_adr_in_use = []

        for row in ip_number.find_in_range(self.ip_min, self.ip_max):
            current_address = long(row['ipnr'])
            if current_address in self.reserved_adr:
                res_adr_in_use.append(IPCalc.long_to_ip(current_address))

        if res_adr_in_use:
            res_adr_in_use.sort()
            raise SubnetError(
                "The following reserved ip's are already in use"
                " on (new?) subnet %s/%s: '%s'." %
                (self.subnet_ip, self.subnet_mask, ', '.join(res_adr_in_use)))
Beispiel #15
0
    def find_used_ips(self, subnet):
        """Returns all ips that are taken on the given subnet in
        ascending order.

        Addresses returned are as xxx.xxx.xxx.xxx, not longs.

        """
        if '.' in subnet:
            ip_number = IPNumber.IPNumber(self._db)
            sub = Subnet.Subnet(self._db)
            ip_key = 'a_ip'
        else:
            ip_number = IPv6Number.IPv6Number(self._db)
            sub = IPv6Subnet.IPv6Subnet(self._db)
            ip_key = 'aaaa_ip'
        ip_number.clear()
        sub.clear()
        sub.find(subnet)
        ret = []
        for row in ip_number.find_in_range(sub.ip_min, sub.ip_max):
            ret.append(row[ip_key])
        return ret
Beispiel #16
0
    def _update_override(self, ip_number_id, dns_owner_id):
        """Handles the updating of the override_reversemap when an
        ARecord is removed."""

        # Select correct IP-variant
        try:
            ipnumber = IPNumber.IPNumber(self._db)
            ipnumber.clear()
            ipnumber.find(ip_number_id)
            ar = ARecord.ARecord(self._db)
        except Errors.NotFoundError:
            ipnumber = IPv6Number.IPv6Number(self._db)
            ar = AAAARecord.AAAARecord(self._db)

        owners = []
        for row in ipnumber.list_override(ip_number_id=ip_number_id):
            if dns_owner_id == row['dns_owner_id']:
                # Always remove the reverse which corresponds to the
                # ARecord which is being removed.
                ipnumber.delete_reverse_override(ip_number_id, dns_owner_id)
            elif row['dns_owner_id'] == None:
                # We know that this IP has been associated with an
                # ARecord.  If PTR generation has been surpressed by
                # setting owner to NULL, we want to remove the reverse
                # to avoid surprises when the IP is reused.
                ipnumber.delete_reverse_override(ip_number_id, None)
            else:
                owners.append(row['dns_owner_id'])

        if len(owners) != 1:
            return

        # The single entry left is redundant if there is only one
        # ARecord referring to the IP.
        rows = ar.list_ext(ip_number_id=ip_number_id)
        if len(rows) == 1 and rows[0]['dns_owner_id'] == owners[0]:
            ipnumber.delete_reverse_override(ip_number_id, owners[0])
Beispiel #17
0
from Cerebrum import Group
from Cerebrum.Utils import Factory

from Cerebrum.modules.dns import ARecord
from Cerebrum.modules.dns import CNameRecord
from Cerebrum.modules.dns import DnsOwner
from Cerebrum.modules.dns import HostInfo
from Cerebrum.modules.dns import IPNumber
from Cerebrum.modules.dns import Utils

sys.argv.extend(["--logger-level", "DEBUG"])
logger = Factory.get_logger("cronjob")
db = Factory.get('Database')()
db.cl_init(change_program='import_dns')
co = Factory.get('Constants')(db)
ipnumber = IPNumber.IPNumber(db)
arecord = ARecord.ARecord(db)
cname = CNameRecord.CNameRecord(db)
dnsowner = DnsOwner.DnsOwner(db)
host = HostInfo.HostInfo(db)
mx_set = DnsOwner.MXSet(db)

# logger.setLevel(logger.debug)
header_splitter = r'^; AUTOGENERATED: do not edit below this line'

class Netgroups(object):
    class MergeRestart(Exception): pass

    def __init__(self, fname, default_zone):
        self._fname = fname
        self._default_zone = default_zone
Beispiel #18
0
    def find_referers(self, ip_number_id=None, dns_owner_id=None,
                      only_type=True, ip_type=dns.IP_NUMBER):
        """Return information about registrations that point to this
        ip-number/dns-owner. If only_type=True, returns a list of
        owner_type.  Otherwise returns a list of (owner_type,
        owner_id) tuples"""

        # We choose classes and record type depending on the ip_type
        # parameter. This is a bit dirty, but reduces the amount of
        # functions required.
        ip_class = IPNumber.IPNumber if (
            ip_type == dns.IP_NUMBER
        ) else IPv6Number.IPv6Number
        record_class = ARecord.ARecord if (
            ip_type == dns.IP_NUMBER
        ) else AAAARecord.AAAARecord
        record_type = dns.A_RECORD if (
            ip_type == dns.IP_NUMBER
        ) else dns.AAAA_RECORD

        ip_key = 'ip_number_id' if (
            ip_type == dns.IP_NUMBER
        ) else 'ipv6_number_id'
        record_key = 'a_record_id' if (
            ip_type == dns.IP_NUMBER
        ) else 'aaaa_record_id'

        # Not including entity-note
        assert not (ip_number_id and dns_owner_id)
        ret = []

        if ip_number_id and ip_type == dns.REV_IP_NUMBER:
            for ipn, key in [
                    (IPNumber.IPNumber(self._db), 'ip_number_id'),
                    (IPv6Number.IPv6Number(self._db), 'ipv6_number_id')]:
                for row in ipn.list_override(ip_number_id=ip_number_id):
                    ret.append((dns.REV_IP_NUMBER, row[key]))

            if only_type:
                return [x[0] for x in ret]
            return ret

        if ip_number_id:
            ipnumber = ip_class(self._db)
            for row in ipnumber.list_override(ip_number_id=ip_number_id):
                ret.append((dns.REV_IP_NUMBER, row[ip_key]))
            arecord = record_class(self._db)
            for row in arecord.list_ext(ip_number_id=ip_number_id):
                ret.append((record_type, row[record_key]))
            if only_type:
                return [x[0] for x in ret]
            return ret
        mx = DnsOwner.MXSet(self._db)
        for row in mx.list_mx_sets(target_id=dns_owner_id):
            ret.append((dns.MX_SET, row['mx_set_id']))
        dns_owner = DnsOwner.DnsOwner(self._db)
        for row in dns_owner.list_srv_records(target_owner_id=dns_owner_id):
            ret.append((dns.SRV_TARGET, row['service_owner_id']))
        cn = CNameRecord.CNameRecord(self._db)
        for row in cn.list_ext(target_owner=dns_owner_id):
            ret.append((dns.CNAME_TARGET, row['cname_id']))
        arecord = record_class(self._db)
        for row in arecord.list_ext(dns_owner_id=dns_owner_id):
            ret.append((record_type, row[record_key]))
        hi = HostInfo.HostInfo(self._db)
        for row in hi.list_ext(dns_owner_id=dns_owner_id):
            ret.append((dns.HOST_INFO, row['host_id'],))
        if only_type:
            return [x[0] for x in ret]
        return ret