Пример #1
0
    def check_for_overlaps(self):
        """Checks if there already are subnets in the database that
        overlap with this subnet.

        Overlap is defined as having an ip_min-ip_max range that
        overlaps with an existing (= in DB) subnet's ip_min-ip_max
        range.

        Raises SubnetError if there are overlaps.

        """
        binds = {"min": self.ip_min, "max": self.ip_max}

        overlap_entries = self.query(
            """SELECT subnet_ip, ip_min, ip_max
               FROM [:table schema=cerebrum name=dns_ipv6_subnet]
               WHERE NOT (:max < ip_min OR :min > ip_max)""", binds)

        if overlap_entries:
            overlaps = [
                "%s/%s" %
                (o['subnet_ip'],
                 IPv6Subnet.calculate_subnet_mask(o['ip_min'], o['ip_max']))
                for o in overlap_entries
            ]
            raise SubnetError(
                "Subnet '%s/%s' overlaps with the following "
                "subnet(s): '%s'" %
                (self.subnet_ip, self.subnet_mask, "', '".join(overlaps)))
Пример #2
0
    def delete(self, perform_checks=True):
        if perform_checks:
            if self.has_adresses_in_use():
                raise SubnetError(
                    "Subnet '%s/%s' cannot be deleted; it has addresses in use" %
                    (self.subnet_ip, self.subnet_mask))

        # Revoke BofhdAuthRoles associated with subnet
        baot = BofhdAuthOpTarget(self._db)
        bar = BofhdAuthRole(self._db)
        targets = [x['op_target_id'] for x in
                   baot.list(entity_id=self.entity_id)]
        if targets:
            for target in targets:
                for x in bar.list(op_target_id=target):
                    bar.revoke_auth(*x)
            bar.commit()

        # Remove BofhdAuthOpTarget associated with subnet
        for x in targets:
            baot.clear()
            try:
                baot.find(x)
                baot.delete()
                baot.commit()
            except NotFoundError:
                pass

        self._db.log_change(self.entity_id, self.const.subnet_delete, None)
        if self.__in_db:
            self.execute("""
            DELETE FROM [:table schema=cerebrum name=dns_subnet]
            WHERE entity_id=:e_id""", {'e_id': self.entity_id})
        self.__super.delete()
Пример #3
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)))
Пример #4
0
    def validate_subnet(subnet):
        """Validates that a subnet specification is correctly
        formatted and with legal values.

        Raises SubnetError if invalid.
        """
        try:
            ip, mask = subnet.split('/')
            mask = int(mask)
        except ValueError:
            raise SubnetError("Not a valid subnet '%s'" % subnet)
        if not IPv6Utils.is_valid_ipv6(ip):
            raise SubnetError("Invalid adress: %s" % ip)
        # TODO 25-08-2015:
        # Since Subnet-masks for IPv6 are not properly implemented yet, this
        # will validate an unspecified subnet mask (''), enabling bofh-users
        # to specify a subnet like this: '2007:700:111:1/'. This should be
        # fixed when/if proper subnet-handling is implemented.
        if mask < 0 or mask > 128:
            raise SubnetError("Invalid subnet mask '%s'; "
                              "outside range 0-128" % mask)
        return True
Пример #5
0
    def delete(self, perform_checks=True):
        if perform_checks:
            if self.has_adresses_in_use():
                raise SubnetError(
                    "Subnet '%s/%s' cannot be deleted; it has addresses in use" % (
                        self.subnet_ip, self.subnet_mask))

        self._db.log_change(self.entity_id, self.const.subnet6_delete, None)
        if self.__in_db:
            self.execute("""
            DELETE FROM [:table schema=cerebrum name=dns_ipv6_subnet]
            WHERE entity_id=:e_id""", {'e_id': self.entity_id})
        self.__super.delete()
Пример #6
0
    def validate_subnet(subnet):
        """Validates that a subnet specification is correctly
        formatted and with legal values.

        Raises SubnetError if invalid.
        """
        try:
            ip, mask = subnet.split('/')
            mask = int(mask)
        except ValueError:
            raise SubnetError("Not a valid subnet '%s'" % subnet)
        if len(ip.split('.')) == 3:
            ip = ip + ".0"
        elif len(ip.split('.')) != 4:
            raise SubnetError("Invalid number of segments in '%s'. "
                              "Should be 3 or 4" % ip)
        for element in ip.split('.'):
            if int(element) < 0 or int(element) > 255:
                raise SubnetError("Element out of range in '%s': '%s'" % (ip,
                                                                      element))
        if mask < 0 or mask > 32:
            raise SubnetError("Invalid subnet mask '%s'; outside range 0-32" % mask)
        return True
Пример #7
0
    def calculate_reserved_addresses(self):
        """TODO: DOC

        """
        # If no_of_reserved_adr is 0, then only the net and broadcast
        # address should be reserved; typically for small, special
        # purpose subnets.
        if self.no_of_reserved_adr == 0:
            self.reserved_adr = set()
            self.reserved_adr.add(self.ip_min)
            # Add the broadcast unless /32 net
            if self.ip_min < self.ip_max:
                self.reserved_adr.add(self.ip_max)
            return

        # First, check that we aren't trying to reserve more addresses
        # than there are in the subnet. Don't count the subnet's
        # address itself, since the number is for counting addresses
        # after it.
        if (self.ip_min + self.no_of_reserved_adr) > self.ip_max:
            raise SubnetError(
                "Trying to reserve %i addresses in a subnet"
                " that has %i addresses available."
                " You can't do that! Because it's *wrong*" %
                (self.no_of_reserved_adr, self.ip_max - self.ip_min))

        # Designate the first X adresses in subnet (not counting the
        # subnet's address itself) as reserved, where X equals the
        # number specifically set as reserved addresses.
        self.reserved_adr = set(x + self.ip_min + 1
                                for x in range(self.no_of_reserved_adr))

        # Make sure the first (subnet address) and last (broadcast)
        # addresses in the subnet is set as reserved.
        self.reserved_adr.add(self.ip_min)
        self.reserved_adr.add(self.ip_max)

        # /22 and /23 nets have some intermediate adresses reserved in
        # order to ease future netsplits.
        if self.subnet_mask == 22:
            self.reserved_adr.update(x + self.ip_min for x in [255, 256] +
                                     [255 * 2 + 1, 255 * 2 + 2])

        if self.subnet_mask == 23:
            self.reserved_adr.update(x + self.ip_min for x in [255, 256])
Пример #8
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)))
Пример #9
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)))
Пример #10
0
 def delete(self, perform_checks=True):
     if perform_checks and self.has_adresses_in_use():
         raise SubnetError(
             "Subnet '%s/%s' cannot be deleted; it has addresses in use" %
             (self.subnet_ip, self.subnet_mask))
     if self.__in_db:
         binds = {'e_id': self.entity_id}
         exists_stmt = """
           SELECT EXISTS (
             SELECT 1
             FROM [:table schema=cerebrum name=dns_ipv6_subnet]
             WHERE entity_id=:e_id
           )
         """
         if self.query_1(exists_stmt, binds):
             delete_stmt = """
             DELETE FROM [:table schema=cerebrum name=dns_ipv6_subnet]
             WHERE entity_id=:e_id"""
             self.execute(delete_stmt, binds)
             self._db.log_change(self.entity_id,
                                 self.clconst.subnet6_delete, None)
     self.__super.delete()
Пример #11
0
    def calculate_reserved_addresses(self):
        """Populates the list over reserved addresses.
        """
        # If no_of_reserved_adr is 0
        if self.no_of_reserved_adr == 0:
            self.reserved_adr = set()
            return

        # First, check that we aren't trying to reserve more addresses
        # than there are in the subnet. Don't count the subnet's
        # address itself, since the number is for counting addresses
        # after it.
        if (self.ip_min + self.no_of_reserved_adr) > self.ip_max:
            raise SubnetError(
                "Trying to reserve %i addresses in a subnet " % self.no_of_reserved_adr +
                "that has %i addresses available. " % (self.ip_max - self.ip_min) +
                "You can't do that! Because it's *wrong*")

        # Designate the first X adresses in subnet as reserved,
        # where X equals the, number specifically set as reserved addresses.
        self.reserved_adr = set([x + self.ip_min for
                                 x in range(self.no_of_reserved_adr)])
Пример #12
0
    def find(self, identifier):
        """Find and instantiate the subnet entity with data from the db.

        @type identifier: mixed
        @param identifier:
            The identifier of the Subnet. Note that the DNS module behaves a
            bit differently than other Cerebrum modules, in that this find
            method accepts other input than entity_id. Possibilities are:

                - A string containing the entity_id, prefixed with 'entity_id:'
                  or 'id:'.

                - A string with a subnet address, e.g. '2002:123:111::/64'.

                - A string with an IPv6 address, e.g. '2001:700:111::0:12'.

        """
        binds = {}
        if identifier is None:
            raise SubnetError("Unable to find IPv6 subnet identified"
                              " by '%s'" % identifier)
        if isinstance(identifier, (int, long)):
            # The proper way of running find()
            where_param = "entity_id = :e_id"
            binds['e_id'] = identifier
        elif identifier.startswith('id:') or identifier.startswith(
                'entity_id:'):
            # E.g. 'id:X' or 'entity_id:X';
            where_param = "entity_id = :e_id"
            try:
                binds['e_id'] = int(identifier.split(':')[1])
            except ValueError:
                raise SubnetError("Entity ID must be an integer")
        elif identifier.find('/') > 0:
            # A '/' indicates a subnet spec: just need the ip
            where_param = "subnet_ip = :subnet_ip"
            subnet_ip = identifier.split('/')[0]
            binds['subnet_ip'] = IPv6Utils.explode(subnet_ip)
        else:
            # Last valid type is simply an IP; need to find correct range
            where_param = "ip_min <= :ip AND ip_max >= :ip"
            binds['ip'] = IPv6Calc.ip_to_long(identifier)
        try:
            (eid, self.subnet_ip, self.ip_min, self.ip_max, self.description,
             self.dns_delegated, self.name_prefix, self.vlan_number,
             self.no_of_reserved_adr) = self.query_1(
                 """ SELECT entity_id, subnet_ip, ip_min, ip_max, description,
                            dns_delegated, name_prefix, vlan_number,
                            no_of_reserved_adr
                     FROM [:table schema=cerebrum name=dns_ipv6_subnet]
                     WHERE %s""" % where_param, binds)
            self.__super.find(eid)
            self.subnet_mask = IPv6Subnet.calculate_subnet_mask(
                self.ip_min, self.ip_max)
            self.calculate_reserved_addresses()
        except NotFoundError:
            raise SubnetError("Unable to find IPv6 subnet identified"
                              " by '%s'" % identifier)

        self.__in_db = True
        self.__updated = []