def range_detail(request, pk): mrange = get_object_or_404(Range, pk=pk) allow = None if mrange.allow == ALLOW_OPTION_VRF: try: allow = [Vrf.objects.get(network=mrange.network)] except ObjectDoesNotExist: allow = [] elif mrange.allow == ALLOW_OPTION_KNOWN: allow = [ALLOW_OPTION_KNOWN] elif mrange.allow == ALLOW_OPTION_LEGACY: allow = [ctnr for ctnr in Ctnr.objects.filter(ranges=mrange)] start_upper = mrange.start_upper start_lower = mrange.start_lower end_upper = mrange.end_upper end_lower = mrange.end_lower range_data, ip_usage_percent = range_usage( two_to_one(start_upper, start_lower), two_to_one(end_upper, end_lower), mrange.ip_type) return render(request, 'range/range_detail.html', { 'obj': mrange, 'obj_type': 'range', 'ranges_table': tablefy((mrange,)), 'range_data': make_paginator(request, range_data, 50), 'attrs_table': tablefy(mrange.rangekeyvalue_set.all()), 'allow_list': allow, 'range_used': "{0}%".format(ip_usage_percent) })
def range_detail(request, pk): mrange = get_object_or_404(Range, pk=pk) if mrange.allow == ALLOW_ANY: allow = ['Any client'] elif mrange.allow == ALLOW_KNOWN: allow = ['Known clients'] else: allow = [] if mrange.allow == ALLOW_VRF: allow += map(str, Vrf.objects.filter(network=mrange.network)) if mrange.allow == ALLOW_LEGACY: allow += map(str, Ctnr.objects.filter(ranges=mrange)) allow.sort(key=lambda x: x.lower()) range_type = mrange.range_type range_data = [] ip_usage_percent = None dynamic_interfaces = [] dynamic_interfaces_page_obj = None if range_type == 'st': start_upper = mrange.start_upper start_lower = mrange.start_lower end_upper = mrange.end_upper end_lower = mrange.end_lower range_data, ip_usage_percent = range_usage( two_to_one(start_upper, start_lower), two_to_one(end_upper, end_lower), mrange.ip_type) else: ip_usage_percent = mrange.range_usage DynamicInterface = get_model('cyder', 'dynamicinterface') dynamic_interfaces = DynamicInterface.objects.filter(range=mrange) dynamic_interfaces_page_obj = make_paginator( request, do_sort(request, dynamic_interfaces), 10) if ip_usage_percent: ip_usage_percent = "{0}%".format(ip_usage_percent) return render(request, 'range/range_detail.html', { 'obj': mrange, 'obj_type': 'range', 'pretty_obj_type': mrange.pretty_type, 'ranges_table': tablefy((mrange,), info=False, request=request), 'range_data': make_paginator(request, range_data, 50), 'range_type': range_type, 'attrs_table': tablefy(mrange.rangeav_set.all(), request=request), 'allow_list': allow, 'range_used': ip_usage_percent, 'dynamic_intr_table': tablefy(dynamic_interfaces_page_obj, info=True, request=request), 'page_obj': dynamic_interfaces_page_obj })
def range_usage(start, end, ip_type): """ Takes a start and end address as integers and returns a range usage list containing tuples of the available ips and lists of contiguously used ip addresses. """ ip_start, ip_end, ipf_q = start_end_filter(start, end, ip_type) record_ip = lambda x: two_to_one(x.ip_upper, x.ip_lower) taken_ips = sorted(chain( AddressRecord.objects.filter(ipf_q), PTR.objects.filter(ipf_q), StaticInterface.objects.filter(ipf_q)), key=record_ip) contiguous_ip_list, total_used = contiguous_ips(taken_ips) total_ips = (end - start) + 1 range_usage_list = [] free_range_start = ip_start for filled_range in contiguous_ip_list: # if the first address in the current contiguous range is greater # than the first free address add that free range of ips to the range # usage list if free_range_start < filled_range[0][0]: range_usage_list.append( ("Free", free_range_start, filled_range[0][0] - 1, json.dumps({"ip_str": str(free_range_start), "ip_type": ip_type}))) # the new free range may start with the next address after the end of # the current filled range free_range_start = filled_range[-1][0] + 1 range_usage_list.append(filled_range) # handle the case where there is an additional free range after the final # filled range if free_range_start < ip_end: range_usage_list.append( ("Free", free_range_start, ip_end, json.dumps({"ip_str": str(free_range_start), "ip_type": ip_type}))) return range_usage_list, int((float(total_used) / total_ips) * 100)
def range_usage(start, end, ip_type): """ Takes a start and end address as integers and returns a range usage list containing tuples of the available ips and lists of contiguously used ip addresses. """ ip_start, ip_end, ipf_q = start_end_filter(start, end, ip_type) record_ip = lambda x: two_to_one(x.ip_upper, x.ip_lower) taken_ips = sorted(chain(AddressRecord.objects.filter(ipf_q), PTR.objects.filter(ipf_q), StaticInterface.objects.filter(ipf_q)), key=record_ip) contiguous_ip_list, total_used = contiguous_ips(taken_ips) total_ips = (end - start) + 1 range_usage_list = [] free_range_start = ip_start for filled_range in contiguous_ip_list: # if the first address in the current contiguous range is greater # than the first free address add that free range of ips to the range # usage list if free_range_start < filled_range[0][0]: range_usage_list.append( ("Free", free_range_start, filled_range[0][0] - 1, json.dumps({ "ip_str": str(free_range_start), "ip_type": ip_type }))) # the new free range may start with the next address after the end of # the current filled range free_range_start = filled_range[-1][0] + 1 range_usage_list.append(filled_range) # handle the case where there is an additional free range after the final # filled range if free_range_start < ip_end: range_usage_list.append(("Free", free_range_start, ip_end, json.dumps({ "ip_str": str(free_range_start), "ip_type": ip_type }))) return range_usage_list, int((float(total_used) / total_ips) * 100)
def get_ip(rec): return two_to_one(rec.ip_upper, rec.ip_lower)
def range_usage(ip_start, ip_end, ip_type, get_objects=True): """Returns ip usage statistics about the range starting at ip_start and ending at ip_end. Given an inclusive contiguous range of positive integers (IP addresses) between `a` and `b` and a list of lists where each sublist contains integers (IP addresses) that are within the range, how many integers between `a` and `b` do not exist in any of the lists; this is what this function calculates. For example: ``` Start = 0 End = 9 Lists = [[1,2,3], [2,3,4]] ``` The integers that do not occur in `Lists` are `0`, `5`, `6`, `7`, `8`, and `9`, so there are 6 integers that do not exist in Lists that satisfy `Start <= n <= End`. Start can be small and End can be very large (the range may be larger than you would want to itterate over). Due to the size of IPv6 ranges, we should not use recursion. There are three types of objects (that we care about) that have IP's associated with them: AddressRecord, PTR, StaticInterface. Because we get objects back as Queryset's that are hard to merge, we have to do this algorithm while retaining all three lists. The gist of the algoritm is as follows:: # Assume the lists are sorted while lists: note the start number (ip) lowest =: of the things in list (PTR, A, INTR), find the lowest difference =: start - lowest.ip total_free +=: difference start =: lowest.ip + 1 if any PTR, A, or INTR has the same IP as lowest: remove those items from their lists """ StaticInterface = get_model('cyder', 'staticinterface') PTR = get_model('cyder', 'ptr') AddressRecord = get_model('cyder', 'addressrecord') istart, iend, ipf_q = start_end_filter(ip_start, ip_end, ip_type) def get_ip(rec): return two_to_one(rec.ip_upper, rec.ip_lower) lists = [ sorted(AddressRecord.objects.filter(ipf_q), key=get_ip), sorted(PTR.objects.filter(ipf_q), key=get_ip), sorted(StaticInterface.objects.filter(ipf_q), key=get_ip) ] free_ranges = [] def cmp_ip_upper_lower(a, b): if a.ip_upper > b.ip_upper: return a elif a.ip_upper < b.ip_upper: return b elif a.ip_lower > b.ip_lower: return a elif a.ip_lower < b.ip_lower: return b else: return a # redundant, maybe? unused = 0 minimum_i = 0 rel_start = int(istart) end = int(iend) # This is translated directly from a recursive implementation. while True: if rel_start > end: break lists = [l for l in lists if l] if not lists: free_ranges.append((rel_start, end)) unused += end - rel_start + 1 break min_list = min(lists, key=lambda x: two_to_one(x[0].ip_upper, x[0].ip_lower)) minimum = min_list[0] minimum_i = two_to_one(minimum.ip_upper, minimum.ip_lower) unused += minimum_i - rel_start if minimum_i != rel_start: free_ranges.append((rel_start, minimum_i - 1)) for l in lists: while (l and l[0].ip_upper == minimum.ip_upper and l[0].ip_lower == minimum.ip_lower): l.pop(0) rel_start = minimum_i + 1 return { 'unused': unused, 'used': int(iend) - int(istart) - unused + 1, 'free_ranges': free_ranges, }
def range_usage(ip_start, ip_end, ip_type, get_objects=True): """Returns ip usage statistics about the range starting at ip_start and ending at ip_end. Given an inclusive contiguous range of positive integers (IP addresses) between `a` and `b` and a list of lists where each sublist contains integers (IP addresses) that are within the range, how many integers between `a` and `b` do not exist in any of the lists; this is what this function calculates. For example: ``` Start = 0 End = 9 Lists = [[1,2,3], [2,3,4]] ``` The integers that do not occur in `Lists` are `0`, `5`, `6`, `7`, `8`, and `9`, so there are 6 integers that do not exist in Lists that satisfy `Start <= n <= End`. Start can be small and End can be very large (the range may be larger than you would want to itterate over). Due to the size of IPv6 ranges, we should not use recursion. There are three types of objects (that we care about) that have IP's associated with them: AddressRecord, PTR, StaticInterface. Because we get objects back as Queryset's that are hard to merge, we have to do this algorithm while retaining all three lists. The gist of the algoritm is as follows:: # Assume the lists are sorted while lists: note the start number (ip) lowest =: of the things in list (PTR, A, INTR), find the lowest difference =: start - lowest.ip total_free +=: difference start =: lowest.ip + 1 if any PTR, A, or INTR has the same IP as lowest: remove those items from their lists """ istart, iend, ipf_q = start_end_filter(ip_start, ip_end, ip_type) def get_ip(rec): return two_to_one(rec.ip_upper, rec.ip_lower) lists = [sorted(AddressRecord.objects.filter(ipf_q), key=get_ip), sorted(PTR.objects.filter(ipf_q), key=get_ip), sorted(StaticInterface.objects.filter(ipf_q), key=get_ip)] free_ranges = [] def cmp_ip_upper_lower(a, b): if a.ip_upper > b.ip_upper: return a elif a.ip_upper < b.ip_upper: return b elif a.ip_lower > b.ip_lower: return a elif a.ip_lower < b.ip_lower: return b else: return a # redundant, maybe? unused = 0 minimum_i = 0 rel_start = int(istart) end = int(iend) # This is translated directly from a recursive implementation. while True: if rel_start > end: break lists = [l for l in lists if l] if not lists: free_ranges.append((rel_start, end)) unused += end - rel_start + 1 break min_list = min(lists, key=lambda x: two_to_one(x[0].ip_upper, x[0].ip_lower)) minimum = min_list[0] minimum_i = two_to_one(minimum.ip_upper, minimum.ip_lower) unused += minimum_i - rel_start if minimum_i != rel_start: free_ranges.append((rel_start, minimum_i - 1)) for l in lists: while (l and l[0].ip_upper == minimum.ip_upper and l[0].ip_lower == minimum.ip_lower): l.pop(0) rel_start = minimum_i + 1 return { 'unused': unused, 'used': int(iend) - int(istart) - unused + 1, 'free_ranges': free_ranges, }
def get_wrapped_ip(self): if self.ip_type == IP_TYPE_4: ip_klass = ipaddr.IPv4Address else: ip_klass = ipaddr.IPv6Address return ip_klass(two_to_one(self.ip_upper, self.ip_lower))