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
Exemple #2
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()
Exemple #3
0
    def _get_reverse_data(self):
        for row in IPv6Number.IPv6Number(db).list(start=self.start,
                                                  stop=self.stop):
            self.ip_numbers[int(row['ipv6_number_id'])] = row

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

        for row in IPv6Number.IPv6Number(db).list_override(start=self.start,
                                                           stop=self.stop):
            self.override_ip.setdefault(int(row['ipv6_number_id']),
                                        []).append(row)
        logger.debug(
            "_get_reverse_ipv6_data -> %i, %i, %i" %
            (len(self.ip_numbers), len(self.a_records), len(self.override_ip)))
Exemple #4
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)
Exemple #5
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)
Exemple #6
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)
Exemple #7
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 []
Exemple #8
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
Exemple #9
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)
Exemple #10
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
    def __init__(self, operator_id):
        """Constructor. Since we are using access control, we need the
        authenticated entity's ID as a parameter.

        """
        self.db = Factory.get('Database')()
        self.db.cl_init(change_program='resource_service')
        self.co = Factory.get('Constants')(self.db)
        self.finder = Utils.Find(self.db, self.default_zone)
        self.subnet = Subnet.Subnet(self.db)
        self.aaaa = AAAARecord.AAAARecord(self.db)
        self.ip = IPv6Number.IPv6Number(self.db)

        # TODO: could we save work by only using a single, shared object of
        # the auth class? It is supposed to be thread safe.
        #self.ba = BofhdAuth(self.db)
        self.operator_id = operator_id
Exemple #12
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)
Exemple #13
0
    def check_reserved_addresses_in_use(self):
        """Raise a SubnetError if this subnet has addresses in use, that are
        really reserved.
        """
        ip_number = IPv6Number.IPv6Number(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 = IPv6Calc.ip_to_long(row['aaaa_ip'])
            if current_address in self.reserved_adr:
                res_adr_in_use.append(row['aaaa_ip'])

        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)))
Exemple #14
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
Exemple #15
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])
Exemple #16
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