diff options
author | Michael Elkins <melkins@tislabs.com> | 2010-07-27 20:45:21 +0000 |
---|---|---|
committer | Michael Elkins <melkins@tislabs.com> | 2010-07-27 20:45:21 +0000 |
commit | 0b23a6b2f42a37db3e615a828d148e274221c8f4 (patch) | |
tree | f9a8f873db0d3054cfebe54081cf054abdb94d75 | |
parent | 25665694c204d928d6b78bebfa7d84c421a11e18 (diff) |
strictly enforce non-overlapping resource ranges in AddressRange and Asn object trees.
add cert member to Roa class to hold a pointer to the resource cert from which all prefixes in the roa derive
svn path=/portal-gui/rpkigui/myrpki/forms.py; revision=3418
-rw-r--r-- | portal-gui/rpkigui/myrpki/forms.py | 70 | ||||
-rw-r--r-- | portal-gui/rpkigui/myrpki/models.py | 3 | ||||
-rw-r--r-- | portal-gui/rpkigui/myrpki/views.py | 29 | ||||
-rwxr-xr-x | portal-gui/scripts/load_csv.py | 41 |
4 files changed, 48 insertions, 95 deletions
diff --git a/portal-gui/rpkigui/myrpki/forms.py b/portal-gui/rpkigui/myrpki/forms.py index e66d8f6d..959d5a20 100644 --- a/portal-gui/rpkigui/myrpki/forms.py +++ b/portal-gui/rpkigui/myrpki/forms.py @@ -60,70 +60,28 @@ def PrefixSplitForm(parent, *args, **kwargs): except ValueError, err: print err raise forms.ValidationError, 'invalid prefix or range' + # we get AssertionError is the range is misordered (hi before lo) + except AssertionError, err: + print err + raise forms.ValidationError, 'invalid prefix or range' pr = parent.as_resource_range() if r.min < pr.min or r.max > pr.max: raise forms.ValidationError, \ 'range is outside parent range' + if r.min == pr.min and r.max == pr.max: + raise forms.ValidationError, \ + 'range is equal to parent' if parent.allocated: - raise forms.ValidationError, 'Prefix is assigned to child' + raise forms.ValidationError, 'prefix is assigned to child' + for p in parent.children.all(): + c = p.as_resource_range() + if c.min <= r.min <= c.max or c.min <= r.max <= c.max: + raise forms.ValidationError, \ + 'overlap with another child prefix: %s' % (c,) + return self.cleaned_data return _wrapper(*args, **kwargs) -#def PrefixSplitForm(prefix, *args, **kwargs): -# class _wrapper(forms.Form): -# lo = forms.IPAddressField() -# hi = forms.IPAddressField() -# -# def clean_lo(self): -# lo = self.cleaned_data.get('lo') -# # convert from string to long representation -# try: -# loaddr = rpki.ipaddrs.parse(lo) -# except socket.error: -# raise forms.ValidationError, 'Invalid IP address string' -# pfx_loaddr = rpki.ipaddrs.parse(prefix.lo) -# pfx_hiaddr = rpki.ipaddrs.parse(prefix.hi) -# if type(loaddr) != type(pfx_hiaddr): -# raise forms.ValidationError, \ -# 'Not the same IP address type as parent' -# if loaddr < pfx_loaddr or loaddr > pfx_hiaddr: -# raise forms.ValidationError, \ -# 'Value out of range of parent prefix' -# return lo -# -# def clean_hi(self): -# hi = self.cleaned_data.get('hi') -# # convert from string to long representation -# try: -# hiaddr = rpki.ipaddrs.parse(hi) -# except socket.error: -# raise forms.ValidationError, 'Invalid IP address string' -# pfx_loaddr = rpki.ipaddrs.parse(prefix.lo) -# pfx_hiaddr = rpki.ipaddrs.parse(prefix.hi) -# if type(hiaddr) != type(pfx_loaddr): -# raise forms.ValidationError, \ -# 'Not the same IP address type as parent' -# if hiaddr < pfx_loaddr or hiaddr > pfx_hiaddr: -# raise forms.ValidationError, \ -# 'Value out of range of parent prefix' -# return hi -# -# def clean(self): -# hi = self.cleaned_data.get('hi') -# lo = self.cleaned_data.get('lo') -# # hi or lo may be None if field validation failed -# if hi and lo: -# # convert from string to long representation -# hiaddr = rpki.ipaddrs.parse(hi) -# loaddr = rpki.ipaddrs.parse(lo) -# if hiaddr < loaddr: -# raise forms.ValidationError, 'Hi value is smaller than Lo' -# if prefix.allocated: -# raise forms.ValidationError, 'Prefix is assigned to child' -# return self.cleaned_data -# -# return _wrapper(*args, **kwargs) - def PrefixAllocateForm(iv, child_set, *args, **kwargs): class _wrapper(forms.Form): child = forms.ModelChoiceField(initial=iv, queryset=child_set, diff --git a/portal-gui/rpkigui/myrpki/models.py b/portal-gui/rpkigui/myrpki/models.py index fc8d4a6d..e2f9cb81 100644 --- a/portal-gui/rpkigui/myrpki/models.py +++ b/portal-gui/rpkigui/myrpki/models.py @@ -194,6 +194,9 @@ class Roa(models.Model): asn = models.IntegerField() active = models.BooleanField() + # the resource cert from which all prefixes for this roa are derived + cert = models.ForeignKey(ResourceCert, related_name='roas') + def __unicode__(self): return u"%s's ROA for %d" % (self.conf, self.asn) diff --git a/portal-gui/rpkigui/myrpki/views.py b/portal-gui/rpkigui/myrpki/views.py index fa9f27e3..7827f706 100644 --- a/portal-gui/rpkigui/myrpki/views.py +++ b/portal-gui/rpkigui/myrpki/views.py @@ -360,16 +360,6 @@ class PrefixAllocateView(PrefixView): def prefix_allocate_view(request, pk): return PrefixAllocateView(request, pk)() -def find_roa(handle, prefix, asid): - '''Find a roa with prefixes from the same resource cert.''' - roa_set = handle.roas.filter(asn=asid) - for c in misc.top_parent(prefix).from_cert.all(): - for r in roa_set: - for req in r.from_roa_request.all(): - if c in misc.top_parent(req.prefix).from_cert.all(): - return r - return None - def add_roa_requests(handle, prefix, asns, max_length): for asid in asns: if debug: @@ -378,15 +368,26 @@ def add_roa_requests(handle, prefix, asns, max_length): if not req_set: if debug: print 'no roa for AS %d containing %s-%d' % (asid, prefix, max_length) - roa = find_roa(handle, prefix, asid) - if not roa: + + # find ROAs for prefixes derived from the same resource cert + # as this prefix + certs = misc.top_parent(prefix).from_cert.all() + roa_set = handle.roas.filter(asn=asid, cert__in=certs) + + # FIXME: currently only creates a ROA/request for the first + # resource cert, not all of them + if roa_set: + roa = roa_set[0] + else: if debug: print 'creating new roa for AS %d containg %s-%d' % (asid, prefix, max_length) # no roa is present for this ASN, create a new one - roa = models.Roa.objects.create(asn=asid, conf=handle, active=False) + roa = models.Roa.objects.create(asn=asid, conf=handle, + active=False, cert=certs[0]) roa.save() - req = models.RoaRequest.objects.create(prefix=prefix, roa=roa, max_length=max_length) + req = models.RoaRequest.objects.create(prefix=prefix, roa=roa, + max_length=max_length) req.save() class PrefixRoaView(PrefixView): diff --git a/portal-gui/scripts/load_csv.py b/portal-gui/scripts/load_csv.py index 76fbaeb2..61ec15b6 100755 --- a/portal-gui/scripts/load_csv.py +++ b/portal-gui/scripts/load_csv.py @@ -48,25 +48,19 @@ print 'processing csv files for resource handle', handle conf = models.Conf.objects.get(handle=handle) # every parent has a favorite -def best_child(parent, parent_range): +def best_child(address_range, parent, parent_range): '''Return the child address range that is the closest match, or returns the arguments if no children.''' - best = None - best_range = None - for q in parent.children.all(): - if best is None: - best = q - best_range = q.as_resource_range() - else: - t = q.as_resource_range() - if t.min >= best_range.min and t.max <= best_range.max: - best = q - best_range = t - if best: - if best.children.all(): - best, best_range = best_child(best, best_range) - return (best, best_range) - + if address_range == parent_range: + return (parent, parent_range) + for q in list(parent.children.all()): # force strict evaluation + t = q.as_resource_range() + if t.min <= address_range.min and t.max >= address_range.max: + return best_child(address_range, q, t) + # check for overlap + if t.min <= address_range.min <= t.max or t.min <= address_range.max <= t.max: + raise RuntimeError, \ + 'can not handle overlapping ranges: %s and %s' % (address_range, t) return parent, parent_range def get_or_create_prefix(address_range): @@ -92,7 +86,7 @@ def get_or_create_prefix(address_range): address_range,) # find the best match among the children + grandchildren - prefix, prefix_range = best_child(prefix, prefix_range) + prefix, prefix_range = best_child(address_range, prefix, prefix_range) print 'best match for %s is %s' % (address_range, prefix) if prefix_range.min != address_range.min or prefix_range.max != address_range.max: @@ -100,7 +94,6 @@ def get_or_create_prefix(address_range): print 'creating new range' prefix = models.AddressRange.objects.create(lo=str(address_range.min), hi=str(address_range.max), parent=prefix) - return prefix def get_or_create_asn(asn): @@ -108,18 +101,14 @@ def get_or_create_asn(asn): from_cert__parent__in=conf.parents.all()) if not asn_set: raise RuntimeError, '%s does not match any received AS range' % (asn,) - best = None - for a in asn_set: - if best is None: - best = a - elif a.lo >= best.lo and a.hi <= best.hi: - best = a + best = best_child(asn, asn_set[0], asn_set[0].as_resource_range())[0] print 'best match for %s is %s' % (asn, best) if best.lo != asn.min or best.hi != asn.max: best = models.Asn.objects.create(lo=asn.min, hi=asn.max, parent=best) return best def do_asns(): + print 'processing', asn_csv for child_handle, asn in csv_reader(asn_csv, columns=2): asn_range = rpki.resource_set.resource_range_as.parse_str(asn) child = conf.children.get(handle=child_handle) @@ -127,6 +116,7 @@ def do_asns(): child.asn.add(asn) def do_prefixes(): + print 'processing', prefix_csv for child_handle, prefix in csv_reader(prefix_csv, columns=2): child = conf.children.get(handle=child_handle) try: @@ -138,6 +128,7 @@ def do_prefixes(): obj.save() def do_roas(): + print 'processing', roa_csv for prefix, asn, group in csv_reader(roa_csv, columns=3): try: rs = rpki.resource_set.roa_prefix_ipv4.parse_str(prefix) |