aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Elkins <melkins@tislabs.com>2010-07-27 20:45:21 +0000
committerMichael Elkins <melkins@tislabs.com>2010-07-27 20:45:21 +0000
commit0b23a6b2f42a37db3e615a828d148e274221c8f4 (patch)
treef9a8f873db0d3054cfebe54081cf054abdb94d75
parent25665694c204d928d6b78bebfa7d84c421a11e18 (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.py70
-rw-r--r--portal-gui/rpkigui/myrpki/models.py3
-rw-r--r--portal-gui/rpkigui/myrpki/views.py29
-rwxr-xr-xportal-gui/scripts/load_csv.py41
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)