Esempio n. 1
0
 def new_prefix(self, vrf, afi, prefix, interface=None, description=None):
     # Enable IPv4 AFI on VRF, if not set
     if afi == "4" and not vrf.afi_ipv4:
         self.info("Enabling IPv4 AFI on VRF %s (%s)" % (vrf.name, vrf.rd))
         if self.to_save:
             vrf.afi_ipv4 = True
             vrf.save()
     # Enable IPv6 AFI on VRF, if not set
     if afi == "6" and not vrf.afi_ipv6:
         self.info("Enabling IPv6 AFI on VRF %s (%s)" % (vrf.name, vrf.rd))
         if self.to_save:
             vrf.afi_ipv6 = True
             vrf.save()
     # Save prefix
     self.info("IPv%s prefix found: %s:%s" % (afi, vrf, prefix))
     self.new_prefixes += [{
         "vrf": vrf,
         "prefix": prefix,
         "object": self.object,
         "interface": interface,
         "description": description
     }]
     if self.to_save:
         Prefix(vrf=vrf, afi=afi, prefix=prefix,
                description=description).save()
Esempio n. 2
0
 def is_discovery_enabled(cls, vrf, afi, address):
     prefix = Prefix.get_parent(vrf, afi, address)
     k = "ip-discovery-enable-%s" % prefix.id
     ds = cache.get(k)
     if ds:
         return ds == "E"
     r = prefix.effective_ip_discovery
     cache.set(k, r, 600)
     return r == "E"
Esempio n. 3
0
 def has_address_permission(self, vrf, address):
     """
     Check discovery has permission to manipulate address
     :param vrf: VRF instance
     :param address: DiscoveredAddress instance
     :return:
     """
     parent = Prefix.get_parent(vrf, "6" if ":" in address.address else "4",
                                address.address)
     if parent:
         return parent.effective_address_discovery == "E"
     return False
Esempio n. 4
0
 def has_prefix_permission(self, vrf, prefix):
     """
     Check discovery has permission to manipulate prefix
     :param vrf: VRF instance
     :param prefix: DiscoveredPrefix instance
     :return:
     """
     parent = Prefix.get_parent(vrf, "6" if ":" in prefix.prefix else "4",
                                prefix.prefix)
     if parent:
         return parent.effective_prefix_discovery == "E"
     return False
Esempio n. 5
0
 def create_prefix(self, prefix):
     """
     Create new prefix
     :param prefix: DiscoveredPrefix instance
     :return:
     """
     if self.is_ignored_prefix(prefix):
         return
     vrf = VRF.get_by_vpn_id(prefix.vpn_id)
     self.ensure_afi(vrf, prefix)
     if not self.has_prefix_permission(vrf, prefix):
         self.logger.debug(
             "Do not creating vpn_id=%s asn=%s prefix=%s: Disabled by policy",
             prefix.vpn_id,
             prefix.asn.asn if prefix.asn else None,
             prefix.prefix,
         )
         metrics["prefix_creation_denied"] += 1
         return
     p = Prefix(
         vrf=vrf,
         prefix=prefix.prefix,
         name=self.get_prefix_name(prefix),
         profile=prefix.profile,
         asn=prefix.asn,
         description=prefix.description,
         source=prefix.source,
     )
     self.logger.info(
         "Creating prefix %s (%s): name=%s profile=%s source=%s",
         p.prefix,
         p.vrf.name,
         p.name,
         p.profile.name,
         p.source,
     )
     p.save()
     self.fire_seen(p)
     metrics["prefix_created"] += 1
Esempio n. 6
0
    def view_quickjump(self, request, vrf_id, afi):
        """
        Quickjump to closest suitable block
        """

        # Interpolate string to valid IPv4 address
        def interpolate_ipv4(s):
            p = s.split(".")
            if len(p) > 4:
                return None
            elif len(p) < 4:
                p += ["0"] * (4 - len(p))
            s = ".".join(p)
            if not is_ipv4(s):
                return None
            return s

        # Interpolate string to valid IPv6 address
        # @todo: implement
        def interpolate_ipv6(s):
            if not is_ipv6(s):
                return None
            return s

        vrf = self.get_object_or_404(VRF, id=int(vrf_id))
        if (afi == "4" and not vrf.afi_ipv4) or (afi == "6"
                                                 and not vrf.afi_ipv6):
            return self.response_forbidden("Invalid AFI")
        if request.POST:
            form = self.QuickJumpForm(request.POST)
            if form.is_valid():
                prefix = form.cleaned_data["jump"].strip()
                # Interpolate prefix
                if afi == "4":
                    prefix = interpolate_ipv4(prefix)
                else:
                    prefix = interpolate_ipv6(prefix)
                if not prefix:
                    self.message_user(request, _("Invalid address"))
                    return self.response_redirect_to_referrer(request)
                # Find prefix
                prefix = Prefix.get_parent(vrf, afi, prefix).prefix
                # Redirect
                self.message_user(
                    request,
                    _("Redirected to %(prefix)s") % {"prefix": prefix})
                return self.response_redirect("ip:ipam:vrf_index", vrf.id, afi,
                                              prefix)
        return self.response_redirect_to_referrer(request)
Esempio n. 7
0
    def view_quickjump(self, request, vrf_id, afi):
        """
        Quickjump to closest suitable block
        """

        # Interpolate string to valid IPv4 address
        def interpolate_ipv4(s):
            p = s.split(".")
            if len(p) > 4:
                return None
            elif len(p) < 4:
                p += ["0"] * (4 - len(p))
            s = ".".join(p)
            if not is_ipv4(s):
                return None
            return s

        # Interpolate string to valid IPv6 address
        # @todo: implement
        def interpolate_ipv6(s):
            if not is_ipv6(s):
                return None
            return s

        vrf = self.get_object_or_404(VRF, id=int(vrf_id))
        if (afi == "4" and not vrf.afi_ipv4) or (afi == "6"
                                                 and not vrf.afi_ipv6):
            return self.response_forbidden("Invalid AFI")
        if request.POST:
            d = orjson.loads(request.body)
            prefix = d["jump"].strip()
            # Interpolate prefix
            if afi == "4":
                prefix = interpolate_ipv4(prefix)
            else:
                prefix = interpolate_ipv6(prefix)
            if not prefix:
                return self.response_bad_request("Invalid address")
            # Find prefix
            prefix = Prefix.get_parent(vrf, afi, prefix)
            return {"id": prefix.id}
        return self.response_redirect_to_referrer(request)
Esempio n. 8
0
 def view_vrf_index(self, request, vrf_id, afi, prefix):
     """
     Display VRF Index
     """
     # Validate
     vrf = self.get_object_or_404(VRF, id=int(vrf_id))
     if (afi == "4" and (not is_ipv4_prefix(prefix)) or not vrf.afi_ipv4) or (
         afi == "6" and (not is_ipv6_prefix(prefix) or not vrf.afi_ipv6)
     ):
         return self.response_forbidden("Invalid prefix")
     prefix = self.get_object_or_404(Prefix, vrf=vrf, afi=afi, prefix=prefix)
     # Get prefix path
     path = []
     p = prefix.parent
     while p:
         path = [p] + path
         p = p.parent
     # List of nested prefixes
     # @todo: prefetch_related
     prefixes = list(prefix.children_set.select_related().order_by("prefix"))
     # Bulk utilization
     Prefix.update_prefixes_usage(prefixes)
     # Get permissions
     user = request.user
     can_view = prefix.can_view(user)
     can_change = prefix.can_change(user)
     can_bind_vc = can_change and Permission.has_perm(user, "ip:ipam:bind_vc")
     can_change_maintainers = user.is_superuser
     can_add_prefix = can_change
     can_add_address = can_change and len(prefixes) == 0
     can_edit_special = prefix.effective_prefix_special_address == "I"
     # Bookmarks
     has_bookmark = prefix.has_bookmark(user)
     bookmarks = PrefixBookmark.user_bookmarks(user, vrf=vrf, afi=afi)
     s_bookmarks = set(b.prefix for b in bookmarks)
     # Add free prefixes
     free_prefixes = list(IP.prefix(prefix.prefix).iter_free([pp.prefix for pp in prefixes]))
     l_prefixes = sorted(
         (
             [(True, IP.prefix(pp.prefix), pp, pp.prefix in s_bookmarks) for pp in prefixes]
             + [(False, pp, None, None) for pp in free_prefixes]
         ),
         key=lambda x: x[1],
     )
     # List of nested addresses
     # @todo: prefetch_related
     addresses = list(prefix.address_set.select_related().order_by("address"))
     # Prepare block info
     prefix_info = [("Network", prefix.prefix)]
     if afi == "4":
         prefix_info += [
             ("Broadcast", prefix.broadcast),
             ("Netmask", prefix.netmask),
             ("Widlcard", prefix.wildcard),
             ("Size", prefix.size),
             ("Usage", prefix.usage_percent),
             ("Usage Address", prefix.address_usage_percent),
         ]
     if addresses:
         prefix_info += [("Used addresses", len(addresses))]
         if afi == "4":
             free = prefix.size - len(addresses)
             prefix_info += [("Free addresses", free - 2 if free >= 2 else free)]
     # Prefix discovery
     dmap = {"E": "Enabled", "D": "Disabled"}
     if prefix.prefix_discovery_policy == "P":
         t = "Profile (%s)" % dmap[prefix.profile.prefix_discovery_policy]
     else:
         t = dmap[prefix.prefix_discovery_policy]
     prefix_info += [("Prefix Discovery", t)]
     # Address discovery
     if prefix.address_discovery_policy == "P":
         t = "Profile (%s)" % dmap[prefix.profile.address_discovery_policy]
     else:
         t = dmap[prefix.address_discovery_policy]
     prefix_info += [("Address Discovery", t)]
     # Source
     prefix_info += [
         (
             "Source",
             {"M": "Manual", "i": "Interface", "w": "Whois Route", "n": "Neighbor"}.get(
                 prefix.source, "-"
             ),
         )
     ]
     #
     # Add custom fields
     for f in CustomField.table_fields("ip_prefix"):
         v = getattr(prefix, f.name)
         prefix_info += [(f.label, v if v is not None else "")]
     # Ranges
     ranges = []
     rs = []
     max_slots = 0
     r_spots = []
     if addresses:
         # Assign ranges colors
         ranges = list(prefix.address_ranges)
         for r, c in zip(ranges, get_colors(len(ranges))):
             r.color = c
             # Schedule ranges
         r_changes = {}  # Address -> (set of entering ranges, set of leaving ranges)
         for r in ranges:
             if r.from_address not in r_changes:
                 r_changes[r.from_address] = (set(), set())
             if r.to_address not in r_changes:
                 r_changes[r.to_address] = (set(), set())
             r_changes[r.from_address][0].add(r)
             r_changes[r.to_address][1].add(r)
             # <!>
             n = (IP.prefix(r.to_address) + 1).address
             if n not in r_changes:
                 r_changes[n] = (set(), set())
         r_spots = list(six.iterkeys(r_changes))
         # Allocate slots
         used_slots = set()
         free_slots = set()
         r_slots = {}  # Range -> slot
         max_slots = 0
         rs = sorted(
             ([IP.prefix(i), d, []] for i, d in six.iteritems(r_changes)), key=itemgetter(0)
         )
         for address, d, x in rs:
             entering, leaving = d
             for r in entering:
                 if not free_slots:
                     free_slots.add(max_slots)
                     max_slots += 1
                 s = free_slots.pop()
                 used_slots.add(s)
                 r_slots[r] = s
             for r in leaving:
                 s = r_slots[r]
                 used_slots.remove(s)
                 free_slots.add(s)
         # Assign ranges to slots
         slots = [None] * max_slots
         for r in rs:
             address, [entering, leaving], _ = r
             for e in entering:
                 slots[r_slots[e]] = e
             r[2] = slots[:]
             for l in leaving:
                 slots[r_slots[l]] = None
         # Assign slots to addresses
         c = [None] * max_slots
         rrs = rs[:]
         cr = rrs.pop(0) if rrs else None
         for a in addresses:
             address = IP.prefix(a.address)
             while cr and address >= cr[0]:
                 c = cr[2]
                 if rrs:
                     cr = rrs.pop(0)
                 else:
                     break
             a.slots = c
     # Address spot
     if can_add_address:
         special_addr = IP.prefix(prefix.prefix).special_addresses
         c = [None] * max_slots
         rrs = rs[:]
         if rrs:
             cr = rrs.pop(0)
         else:
             cr = None
         spot = []
         for a in self.get_prefix_spot(prefix, extra=r_spots):
             if cr and a is not None and a == cr[0]:
                 c = [None if cc is None else cc.id for cc in cr[2]]
                 if rrs:
                     cr = rrs.pop(0)
             spot += [(None if a is None else a.address, c, a in special_addr)]
         spot = ujson.dumps(spot)
     else:
         spot = None
     can_ping = spot is not None and len([a for a in addresses if a.managed_object]) > 0
     # Build custom styles
     styles = {}
     if prefix.profile.style:
         styles[prefix.profile.style.css_class_name] = prefix.profile.style.css
     for p in prefixes:
         if p.profile.style and p.profile.style.css_class_name not in styles:
             styles[p.profile.style.css_class_name] = p.profile.style.css
     for a in addresses:
         if a.profile.style and a.profile.style.css_class_name not in styles:
             styles[a.profile.style.css_class_name] = a.profile.style.css
     styles = "\n".join(six.itervalues(styles))
     # Render
     return self.render(
         request,
         "vrf_index.html.j2",
         user=request.user,
         vrf=vrf,
         prefix=prefix,
         path=path,
         prefixes=prefixes,
         addresses=addresses,
         prefix_info=prefix_info,
         display_empty_message=not addresses and not prefixes,
         can_view=can_view,
         can_change=can_change,
         can_bind_vc=can_bind_vc,
         can_change_maintainers=can_change_maintainers,
         can_add_prefix=can_add_prefix,
         can_add_address=can_add_address,
         can_edit_special=can_edit_special,
         has_bookmark=has_bookmark,
         bookmarks=bookmarks,
         spot=spot,
         can_ping=can_ping,
         styles=styles,
         ranges=ranges,
         max_slots=max_slots,
         l_prefixes=l_prefixes,
     )
Esempio n. 9
0
 def prefix_contents(self, request, prefix):
     vrf = prefix.vrf
     # List of nested prefixes
     # @todo: prefetch_related
     prefixes = list(
         prefix.children_set.select_related().order_by("prefix"))
     # Bulk utilization
     Prefix.update_prefixes_usage(prefixes)
     # Free prefixes
     free_prefixes = list(
         IP.prefix(prefix.prefix).iter_free([pp.prefix for pp in prefixes]))
     # Get permissions
     user = request.user
     can_view = prefix.can_view(user)
     can_change = prefix.can_change(user)
     can_bind_vc = can_change and Permission.has_perm(
         user, "ip:ipam:bind_vc")
     can_change_maintainers = user.is_superuser
     can_add_prefix = can_change
     can_add_address = can_change and len(prefixes) == 0
     # Bookmarks
     has_bookmark = prefix.has_bookmark(user)
     bookmarks = set(b.prefix for b in PrefixBookmark.user_bookmarks(
         user, vrf=vrf, afi=prefix.afi))
     l_prefixes = sorted(
         ([(IP.prefix(pp.prefix), pp, pp.prefix in bookmarks)
           for pp in prefixes] + [(pp, None, False)
                                  for pp in free_prefixes]),
         key=lambda x: x[0],
     )
     # List of nested addresses
     addresses = list(
         prefix.address_set.select_related().order_by("address"))
     # Ranges
     ranges = []
     rs = []
     max_slots = 0
     r_spots = []
     allocated_addresses = set()
     if addresses:
         # Assign ranges colors
         ranges = list(prefix.address_ranges)
         for r, c in zip(ranges, get_colors(len(ranges))):
             r.color = c
             # Schedule ranges
         r_changes = {
         }  # Address -> (set of entering ranges, set of leaving ranges)
         for r in ranges:
             if r.from_address not in r_changes:
                 r_changes[r.from_address] = (set(), set())
             if r.to_address not in r_changes:
                 r_changes[r.to_address] = (set(), set())
             r_changes[r.from_address][0].add(r)
             r_changes[r.to_address][1].add(r)
             # <!>
             n = (IP.prefix(r.to_address) + 1).address
             if n not in r_changes:
                 r_changes[n] = (set(), set())
         r_spots = list(r_changes)
         # Allocate slots
         used_slots = set()
         free_slots = set()
         r_slots = {}  # Range -> slot
         max_slots = 0
         rs = sorted([[IP.prefix(i), d, []] for i, d in r_changes.items()],
                     key=itemgetter(0))
         for address, d, x in rs:
             entering, leaving = d
             for r in entering:
                 if not free_slots:
                     free_slots.add(max_slots)
                     max_slots += 1
                 spt = free_slots.pop()
                 used_slots.add(spt)
                 r_slots[r] = spt
             for r in leaving:
                 spt = r_slots[r]
                 used_slots.remove(spt)
                 free_slots.add(spt)
         # Assign ranges to slots
         slots = [None] * max_slots
         for r in rs:
             address, [entering, leaving], _ = r
             for e in entering:
                 slots[r_slots[e]] = e
             r[2] = slots[:]
             for ll in leaving:
                 slots[r_slots[ll]] = None
         # Assign slots to addresses
         c = [None] * max_slots
         rrs = rs[:]
         cr = rrs.pop(0) if rrs else None
         for a in addresses:
             allocated_addresses.add(str(a.address))
             address = IP.prefix(a.address)
             while cr and address >= cr[0]:
                 c = cr[2]
                 if rrs:
                     cr = rrs.pop(0)
                 else:
                     break
             a.slots = c
     # Address spot
     if can_add_address:
         c = [None] * max_slots
         rrs = rs[:]
         if rrs:
             cr = rrs.pop(0)
         else:
             cr = None
         spot = []
         for a in self.get_prefix_spot(prefix, extra=r_spots):
             if cr and a is not None and a == cr[0]:
                 c = [None if cc is None else cc.id for cc in cr[2]]
                 if rrs:
                     cr = rrs.pop(0)
             spot += [(None if a is None else a.address, c)]
         # spot += [(None if a is None else a.address, c, a in special_addr)]
         # spot = ujson.dumps(spot)
         # spot = JSONEncoder(ensure_ascii=False).encode(spot)
     else:
         spot = None
     can_ping = spot is not None and len(
         [a for a in addresses if a.managed_object]) > 0
     prefix_info = self.get_info_block(prefix.afi, prefix, addresses)
     path = [Prefix.objects.get(id=pp) for pp in prefix.get_path()]
     return {
         "id":
         prefix.id,
         "name":
         prefix.prefix,
         "vrf":
         prefix.vrf.id,
         "vrf__label":
         "%s (%s)" % (prefix.vrf.name, prefix.vrf.vpn_id),
         "description":
         prefix.description,
         "afi":
         prefix.afi,
         "profile":
         prefix.profile.name,
         "state":
         prefix.state.name,
         "maintainers": [m.username for m in prefix.maintainers],
         "has_bookmark":
         has_bookmark,
         "permissions": {
             "view": can_view,
             "change": can_change,
             "bind_vc": can_bind_vc,
             "change_maintainers": can_change_maintainers,
             "add_prefix": can_add_prefix,
             "delete_prefix": True,
             "add_address": can_add_address,
             "ping": can_ping,
         },
         "path": [{
             "id": p.id,
             "parent_id": p.parent_id,
             "name": p.prefix
         } for p in path],
         "prefixes": [{
             "id": p.id,
             "name": p.prefix,
             "has_bookmark": is_bookmarks,
             "description": p.description,
             "afi": p.afi,
             "project": p.project.code if p.project else None,
             "as": "AS%d" % p.asn.asn if p.asn else None,
             "vc": p.vc.name if p.vc else None,
             "tt": p.tt,
             "usage": p.usage_percent,
             "address_usage": p.address_usage_percent,
             "labels": p.labels,
             "state": p.state.name,
             "state_desc": p.state.description,
             "isFree": False,
         } if p else {
             "name": ip.prefix,
             "isFree": True
         } for ip, p, is_bookmarks in l_prefixes],
         "addresses":
         sorted(
             [{
                 "id":
                 a.id,
                 "name":
                 a.name,
                 "address":
                 a.address,
                 "state":
                 a.state.name,
                 "fqdn":
                 a.fqdn if a.fqdn else None,
                 "mac":
                 a.mac if a.mac else None,
                 "mo_id":
                 a.managed_object.id if a.managed_object else None,
                 "mo_name":
                 a.managed_object.name if a.managed_object else None,
                 "is_router":
                 a.managed_object.is_router if a.managed_object else None,
                 "project":
                 a.project.code if a.project else None,
                 "subinterface":
                 a.subinterface if a.subinterface else None,
                 "short_desc":
                 a.short_description,
                 "desc":
                 a.description,
                 "source": {
                     "M": "Manual",
                     "i": "Interface",
                     "m": "Mgmt",
                     "d": "DHCP",
                     "n": "Neighbor",
                 }.get(a.source, "-"),
                 "tt":
                 a.tt,
                 "labels":
                 a.labels,
                 "isFree":
                 False,
             } for a in addresses] + ([{
                 "address": z[0],
                 "isFree": True
             } for z in spot if str(z[0]) not in allocated_addresses]
                                      if spot else []),
             key=lambda x: IP.prefix(x["address"]),
         ),
         "info":
         dict(prefix_info),
         "ranges": [{
             "name": r.name,
             "description": r.description,
             "from_address": r.from_address,
             "to_address": r.to_address,
             "color": r.color,
         } for r in ranges],
         "bookmarks": [{
             "id": b.id,
             "text": b.prefix
         } for b in PrefixBookmark.user_bookmarks(
             user, vrf=vrf, afi=prefix.afi)],
     }