aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rpkid/rpki/gui/app/forms.py45
-rw-r--r--rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html50
-rw-r--r--rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html58
-rw-r--r--rpkid/rpki/gui/app/templates/app/roarequest_form.html40
-rw-r--r--rpkid/rpki/gui/app/urls.py1
-rw-r--r--rpkid/rpki/gui/app/views.py121
6 files changed, 191 insertions, 124 deletions
diff --git a/rpkid/rpki/gui/app/forms.py b/rpkid/rpki/gui/app/forms.py
index 2ddd1dbd..2fcceda2 100644
--- a/rpkid/rpki/gui/app/forms.py
+++ b/rpkid/rpki/gui/app/forms.py
@@ -22,6 +22,7 @@ from rpki.resource_set import (resource_range_as, resource_range_ipv4,
resource_range_ipv6)
from rpki.gui.app import models
from rpki.exceptions import BadIPResource
+from rpki.gui.app.glue import str_to_resource_range
class AddConfForm(forms.Form):
@@ -153,23 +154,19 @@ class ROARequest(forms.Form):
def _as_resource_range(self):
prefix = self.cleaned_data.get('prefix')
- try:
- r = resource_range_ipv4.parse_str(prefix)
- except BadIPResource:
- r = resource_range_ipv6.parse_str(prefix)
- return r
+ return str_to_resource_range(prefix)
def clean_asn(self):
value = self.cleaned_data.get('asn')
if value < 0:
- raise forms.ValidationError, 'AS must be a positive value or 0'
+ raise forms.ValidationError('AS must be a positive value or 0')
return value
def clean_prefix(self):
try:
r = self._as_resource_range()
except:
- raise forms.ValidationError, 'invalid IP address'
+ raise forms.ValidationError('invalid IP address')
return str(r)
def clean_max_prefixlen(self):
@@ -178,8 +175,7 @@ class ROARequest(forms.Form):
if v[0] == '/':
v = v[1:] # allow user to specify /24
if int(v) < 0:
- raise forms.ValidationError, \
- 'max prefix length must be positive or 0'
+ raise forms.ValidationError('max prefix length must be positive or 0')
return v
def clean(self):
@@ -188,8 +184,7 @@ class ROARequest(forms.Form):
max_prefixlen = self.cleaned_data.get('max_prefixlen')
max_prefixlen = int(max_prefixlen) if max_prefixlen else r.prefixlen()
if max_prefixlen < r.prefixlen():
- raise forms.ValidationError, \
- 'max prefix length must be greater than or equal to the prefix length'
+ raise forms.ValidationError('max prefix length must be greater than or equal to the prefix length')
if max_prefixlen > r.datum_type.bits:
raise forms.ValidationError, \
'max prefix length (%d) is out of range for IP version (%d)' % (max_prefixlen, r.datum_type.bits)
@@ -198,6 +193,34 @@ class ROARequest(forms.Form):
return self.cleaned_data
+class ROARequestConfirm(forms.Form):
+ asn = forms.IntegerField(widget=forms.HiddenInput)
+ prefix = forms.CharField(widget=forms.HiddenInput)
+ max_prefixlen = forms.IntegerField(widget=forms.HiddenInput)
+
+ def clean_asn(self):
+ value = self.cleaned_data.get('asn')
+ if value < 0:
+ raise forms.ValidationError('AS must be a positive value or 0')
+ return value
+
+ def clean_prefix(self):
+ try:
+ r = str_to_resource_range(self.cleaned_data.get('prefix'))
+ except BadIPResource:
+ raise forms.ValidationError('invalid prefix')
+ return str(r)
+
+ def clean(self):
+ try:
+ r =str_to_resource_range(self.cleaned_data.get('prefix'))
+ if r.prefixlen() > self.cleaned_data.get('max_prefixlen'):
+ raise forms.ValidationError('max length is smaller than mask')
+ except BadIPResource:
+ pass
+ return self.cleaned_data
+
+
def AddASNForm(qs):
"""
Generate a form class which only allows specification of ASNs contained
diff --git a/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html b/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html
index a0e4b54d..4c8228b6 100644
--- a/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html
+++ b/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html
@@ -1,20 +1,19 @@
{% extends "app/app_base.html" %}
{% block content %}
-
<div class='page-header'>
<h1>Delete ROA Prefix</h1>
</div>
<div class='row'>
<div class='span8'>
- <div class='alert-message box-message warning'>
- <p><strong>Please confirm</strong> that you would like to delete the following ROA Request:
+ <div class='alert-message block-message warning'>
+ <p><strong>Please confirm</strong> that you would like to delete the following ROA Request. The table to the right indicates how validation status for matching routes may change.
<table style='condensed-table'>
<tr>
<th>Prefix</th>
- <th>Max Len</th>
+ <th>Max Length</th>
<th>AS</th>
<tr>
<td>{{ object.prefix }}/{{ object.prefixlen }}</td>
@@ -30,31 +29,26 @@
<a class='btn' href="{% url rpki.gui.app.views.roa_list %}">Cancel</a>
</div>
</form>
-
</div>
</div>
-<div class='span8 offset8'>
-<p>This table indicates what the validation status for the routing entries
-that are covered by this ROA request will be if this ROA request is deleted:
-
-<table style='zebra-striped condensed-table'>
- <tr>
- <th>Prefix</th>
- <th>Origin AS</th>
- <th>Validation Status</th>
- </tr>
- {% for r in routes %}
- <tr>
- <td>{{ r.get_prefix_display }}</td>
- <td>{{ r.asn }}</td>
- <td><span class='label {{ r.status_label }}'>{{ r.status }}</span></td>
- </tr>
- {% endfor %}
-</table>
-</div><!-- /span8 -->
+ <div class='span8'>
+ <h2>Matching Routes</h2>
+
+ <table style='zebra-striped condensed-table'>
+ <tr>
+ <th>Prefix</th>
+ <th>Origin AS</th>
+ <th>Validation Status</th>
+ </tr>
+ {% for r in routes %}
+ <tr>
+ <td>{{ r.get_prefix_display }}</td>
+ <td>{{ r.asn }}</td>
+ <td><span class='label {{ r.status_label }}'>{{ r.status }}</span></td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div><!-- /span8 -->
</div><!-- /row -->
-
-{% endblock %}
-
-<!-- vim:set sw=2: -->
+{% endblock content %}
diff --git a/rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html b/rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html
new file mode 100644
index 00000000..99428875
--- /dev/null
+++ b/rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html
@@ -0,0 +1,58 @@
+{% extends "app/app_base.html" %}
+
+{% block content %}
+<div class='page-title'>
+ <h1>Create ROA</h1>
+</div>
+
+<div class='row'>
+ <div class='span8'>
+ <div class='alert-message block-message warning'>
+ <p><strong>Please confirm</strong> that you would like to create the following ROA.
+ The table on the right shows how the validation status may change as a result.
+
+ <table class='condensed-table'>
+ <tr>
+ <th>AS</th>
+ <th>Prefix</th>
+ <th>Max Length</th>
+ </tr>
+ <tr>
+ <td>{{ asn }}</td>
+ <td>{{ prefix }}</td>
+ <td>{{ max_prefixlen }}</td>
+ </tr>
+ </table>
+
+ <form method='POST' action='{% url rpki.gui.app.views.roa_create_confirm %}'>
+ {% csrf_token %}
+ {% include "app/bootstrap_form.html" %}
+ <div class='alert-actions'>
+ <input class='btn primary' type='submit' value='Create'/>
+ <a class='btn' href='{% url rpki.gui.app.views.roa_list %}'>Cancel</a>
+ </div>
+ </form>
+ </div><!-- /alert-message -->
+ </div>
+
+ <div class='span8'>
+ <h2>Matched Routes</h2>
+
+ <table style='zebra-striped condensed-table'>
+ <tr>
+ <th>Prefix</th>
+ <th>Origin AS</th>
+ <th>Validation Status</th>
+ </tr>
+ {% for r in routes %}
+ <tr>
+ <td>{{ r.get_prefix_display }}</td>
+ <td>{{ r.asn }}</td>
+ <td><span class='label {{ r.status_label }}'>{{ r.status }}</span></td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+
+</div>
+{% endblock content %}
diff --git a/rpkid/rpki/gui/app/templates/app/roarequest_form.html b/rpkid/rpki/gui/app/templates/app/roarequest_form.html
index 83759120..5385cab0 100644
--- a/rpkid/rpki/gui/app/templates/app/roarequest_form.html
+++ b/rpkid/rpki/gui/app/templates/app/roarequest_form.html
@@ -1,42 +1,16 @@
{% extends "app/app_base.html" %}
{% block content %}
-
<div class='page-title'>
<h1>Create ROA</h1>
</div>
-<div class='row'>
- <div class='span8'>
- <form method='POST' action='{{ request.get_full_path }}'>
- {% csrf_token %}
- {% include "app/bootstrap_form.html" %}
- <div class='actions'>
- <input class='btn primary' type='submit' value='Create'/>
- <a class='btn' href='{% url rpki.gui.app.views.roa_list %}'>Cancel</a>
- </div>
- </form>
- </div>
- <div class='span8 offset8'>
- <p>Matched Routes
-
- <table style='zebra-striped condensed-table'>
- <tr>
- <th>Prefix</th>
- <th>Origin AS</th>
- <th>Validation Status</th>
- </tr>
- {% for r in routes %}
- <tr>
- <td>{{ r.get_prefix_display }}</td>
- <td>{{ r.asn }}</td>
- <td><span class='label {{ r.status_label }}'>{{ r.status }}</span></td>
- </tr>
- {% endfor %}
- </table>
+<form method='POST' action='{{ request.get_full_path }}'>
+ {% csrf_token %}
+ {% include "app/bootstrap_form.html" %}
+ <div class='actions'>
+ <input class='btn primary' type='submit' value='Create'/>
+ <a class='btn' href='{% url rpki.gui.app.views.roa_list %}'>Cancel</a>
</div>
-</div>
-
+</form>
{% endblock content %}
-
-{# vim:set sw=2: #}
diff --git a/rpkid/rpki/gui/app/urls.py b/rpkid/rpki/gui/app/urls.py
index b2e30b12..cfe82777 100644
--- a/rpkid/rpki/gui/app/urls.py
+++ b/rpkid/rpki/gui/app/urls.py
@@ -54,6 +54,7 @@ urlpatterns = patterns('',
(r'^repo/(?P<pk>\d+)/delete$', views.repository_delete),
(r'^roa/$', views.roa_list),
(r'^roa/create$', views.roa_create),
+ (r'^roa/confirm$', views.roa_create_confirm),
(r'^roa/(?P<pk>\d+)$', views.roa_detail),
(r'^roa/(?P<pk>\d+)/delete$', views.roa_delete),
(r'^routes/$', views.route_view),
diff --git a/rpkid/rpki/gui/app/views.py b/rpkid/rpki/gui/app/views.py
index 795080fc..b76495c0 100644
--- a/rpkid/rpki/gui/app/views.py
+++ b/rpkid/rpki/gui/app/views.py
@@ -428,7 +428,6 @@ def roa_create(request):
"""
- routes = []
if request.method == 'POST':
form = forms.ROARequest(request.POST, request.FILES)
if form.is_valid():
@@ -437,61 +436,79 @@ def roa_create(request):
rng = form._as_resource_range() # FIXME calling "private" method
max_prefixlen = int(form.cleaned_data.get('max_prefixlen'))
- if form.cleaned_data.get('confirmed'):
- roarequests = models.ROARequest.objects.filter(issuer=conf,
- asn=asn)
- if roarequests:
- # FIXME need to handle the case where there are
- # multiple ROAs for the same AS due to prefixes
- # delegated from different resource certs.
- roa = roarequests[0]
- else:
- roa = models.ROARequest.objects.create(issuer=conf,
- asn=asn)
- version = 'IPv4' if isinstance(rng,
- resource_range_ipv4) else 'IPv6'
- roa.prefixes.create(version=version, prefix=str(rng.min),
- prefixlen=rng.prefixlen(), max_prefixlen=max_prefixlen)
- return http.HttpResponseRedirect(reverse(roa_list))
- else:
- form = forms.ROARequest(initial={
- 'asn': form.cleaned_data.get('asn'),
- 'prefix': form.cleaned_data.get('prefix'),
- 'max_prefixlen': form.cleaned_data.get('max_prefixlen'),
- 'confirmed': True})
-
- # find list of matching routes
- match = roa_match(rng)
- for route, roas in match:
- validate_route(route, roas)
- # tweak the validation status due to the presence of the
- # new ROA. Don't need to check the prefix bounds here
- # because all the matches routes will be covered by this
- # new ROA
- if route.status == 'unknown':
- # if the route was previously unknown (no covering
- # ROAs), then:
- # if the AS matches, it is valid, otherwise invalid
- if (route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen):
- route.status = 'valid'
- route.status_label = 'success'
- else:
- route.status = 'invalid'
- route.status_label = 'important'
- elif route.status == 'invalid':
- # if the route was previously invalid, but this new ROA
- # matches the ASN, it is now valid
- if route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen:
- route.status = 'valid'
- route.status_label = 'success'
-
- routes.append(route)
+ # find list of matching routes
+ routes = []
+ match = roa_match(rng)
+ for route, roas in match:
+ validate_route(route, roas)
+ # tweak the validation status due to the presence of the
+ # new ROA. Don't need to check the prefix bounds here
+ # because all the matches routes will be covered by this
+ # new ROA
+ if route.status == 'unknown':
+ # if the route was previously unknown (no covering
+ # ROAs), then:
+ # if the AS matches, it is valid, otherwise invalid
+ if (route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen):
+ route.status = 'valid'
+ route.status_label = 'success'
+ else:
+ route.status = 'invalid'
+ route.status_label = 'important'
+ elif route.status == 'invalid':
+ # if the route was previously invalid, but this new ROA
+ # matches the ASN, it is now valid
+ if route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen:
+ route.status = 'valid'
+ route.status_label = 'success'
+
+ routes.append(route)
+
+ prefix = str(rng)
+ form = forms.ROARequestConfirm(initial={'asn': asn,
+ 'prefix': prefix,
+ 'max_prefixlen': max_prefixlen})
+ return render(request, 'app/roarequest_confirm_form.html',
+ {'form': form,
+ 'asn': asn,
+ 'prefix': prefix,
+ 'max_prefixlen': max_prefixlen,
+ 'routes': routes})
else:
form = forms.ROARequest()
- return render(request, 'app/roarequest_form.html',
- {'form': form, 'routes': routes})
+ return render(request, 'app/roarequest_form.html', {'form': form})
+
+
+@handle_required
+def roa_create_confirm(request):
+ conf = request.session['handle']
+
+ if request.method == 'POST':
+ form = forms.ROARequestConfirm(request.POST, request.FILES)
+ if form.is_valid():
+ asn = form.cleaned_data.get('asn')
+ prefix = form.cleaned_data.get('prefix')
+ rng = glue.str_to_resource_range(prefix)
+ max_prefixlen = form.cleaned_data.get('max_prefixlen')
+ roarequests = models.ROARequest.objects.filter(issuer=conf,
+ asn=asn)
+ if roarequests:
+ # FIXME need to handle the case where there are
+ # multiple ROAs for the same AS due to prefixes
+ # delegated from different resource certs.
+ roa = roarequests[0]
+ else:
+ roa = models.ROARequest.objects.create(issuer=conf,
+ asn=asn)
+ v = 'IPv4' if isinstance(rng, resource_range_ipv4) else 'IPv6'
+ roa.prefixes.create(version=v, prefix=str(rng.min),
+ prefixlen=rng.prefixlen(),
+ max_prefixlen=max_prefixlen)
+ return http.HttpResponseRedirect(reverse(roa_list))
+ else:
+ return http.HttpResponseRedirect(reverse(roa_create))
@handle_required
def roa_list(request):