aboutsummaryrefslogtreecommitdiff
path: root/rpki/gui/app/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpki/gui/app/views.py')
-rw-r--r--rpki/gui/app/views.py87
1 files changed, 67 insertions, 20 deletions
diff --git a/rpki/gui/app/views.py b/rpki/gui/app/views.py
index dfd36dbb..bf152f8e 100644
--- a/rpki/gui/app/views.py
+++ b/rpki/gui/app/views.py
@@ -27,6 +27,7 @@ from tempfile import NamedTemporaryFile
import cStringIO
import csv
import logging
+import lxml.etree
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
@@ -38,8 +39,8 @@ from django.contrib.auth.models import User
from django.views.generic import DetailView, ListView, DeleteView, FormView
from django.core.paginator import Paginator, InvalidPage
from django.forms.formsets import formset_factory, BaseFormSet
-import django.db.models
from django.contrib import messages
+from django.db.models import Q
from rpki.irdb import Zookeeper, ChildASN, ChildNet, ROARequestPrefix
from rpki.gui.app import models, forms, glue, range_list
@@ -146,19 +147,28 @@ def generic_import(request, queryset, configure, form_class=None,
# expects it.
if handle == '':
handle = None
- # configure_repository returns None, so can't use tuple expansion
- # here. Unpack the tuple below if post_import_redirect is None.
- r = configure(z, tmpf.name, handle)
- # force rpkid run now
- z.synchronize_ca(poke=True)
- os.remove(tmpf.name)
- if post_import_redirect:
- url = post_import_redirect
+ try:
+ # configure_repository returns None, so can't use tuple expansion
+ # here. Unpack the tuple below if post_import_redirect is None.
+ r = configure(z, tmpf.name, handle)
+ except lxml.etree.XMLSyntaxError as e:
+ logger.exception('caught XMLSyntaxError while parsing uploaded file')
+ messages.error(
+ request,
+ 'The uploaded file has an invalid XML syntax'
+ )
else:
- _, handle = r
- url = queryset.get(issuer=conf,
- handle=handle).get_absolute_url()
- return http.HttpResponseRedirect(url)
+ # force rpkid run now
+ z.synchronize_ca(poke=True)
+ if post_import_redirect:
+ url = post_import_redirect
+ else:
+ _, handle = r
+ url = queryset.get(issuer=conf,
+ handle=handle).get_absolute_url()
+ return http.HttpResponseRedirect(url)
+ finally:
+ os.remove(tmpf.name)
else:
form = form_class()
@@ -622,7 +632,6 @@ def get_covered_routes(rng, max_prefixlen, asn):
return routes
-
@handle_required
def roa_create(request):
"""Present the user with a form to create a ROA.
@@ -708,20 +717,58 @@ def roa_create_multi(request):
formset = formset_factory(forms.ROARequestFormFactory(conf), extra=extra)(initial=init)
elif request.method == 'POST':
formset = formset_factory(forms.ROARequestFormFactory(conf), extra=0)(request.POST, request.FILES)
- if formset.is_valid():
+ # We need to check .has_changed() because .is_valid() will return true
+ # if the user clicks the Preview button without filling in the blanks
+ # in the ROA form, leaving the form invalid from this view's POV.
+ if formset.has_changed() and formset.is_valid():
routes = []
v = []
+ query = Q() # for matching routes
+ roas = []
for form in formset:
asn = form.cleaned_data['asn']
rng = resource_range_ip.parse_str(form.cleaned_data['prefix'])
max_prefixlen = int(form.cleaned_data['max_prefixlen'])
- # FIXME: This won't do the right thing in the event that a
- # route is covered by multiple ROAs created in the form.
- # You will see duplicate entries, each with a potentially
- # different validation status.
- routes.extend(get_covered_routes(rng, max_prefixlen, asn))
+ protect_children = form.cleaned_data['protect_children']
+
+ roas.append((rng, max_prefixlen, asn, protect_children))
v.append({'prefix': str(rng), 'max_prefixlen': max_prefixlen,
'asn': asn})
+
+ query |= Q(prefix_min__gte=rng.min, prefix_max__lte=rng.max)
+
+ for rt in RouteOrigin.objects.filter(query):
+ status = rt.status # cache the value
+ newstatus = status
+ if status == 'unknown':
+ # possible change to valid or invalid
+ for rng, max_prefixlen, asn, protect in roas:
+ if rng.min <= rt.prefix_min and rng.max >= rt.prefix_max:
+ # this route is covered
+ if asn == rt.asn and rt.prefixlen <= max_prefixlen:
+ newstatus = 'valid'
+ break # no need to continue for this route
+ else:
+ newstatus = 'invalid'
+ elif status == 'invalid':
+ # possible change to valid
+ for rng, max_prefixlen, asn, protect in roas:
+ if rng.min <= rt.prefix_min and rng.max >= rt.prefix_max:
+ # this route is covered
+ if asn == rt.asn and rt.prefixlen <= max_prefixlen:
+ newstatus = 'valid'
+ break # no need to continue for this route
+
+ if status != newstatus:
+ if protect_children and newstatus == 'invalid' and conf.child_routes.filter(pk=rt.pk).exists():
+ rng = rt.as_resource_range()
+ v.append({'prefix': str(rng),
+ 'max_prefixlen': rng.prefixlen,
+ 'asn': rt.asn})
+ newstatus = 'valid'
+ rt.newstatus = newstatus # I"M A MUHNKAY!!!
+ routes.append(rt)
+
# if there were no rows, skip the confirmation step
if v:
formset = formset_factory(forms.ROARequestConfirm, extra=0)(initial=v)