aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Elkins <melkins@tislabs.com>2012-01-17 05:02:19 +0000
committerMichael Elkins <melkins@tislabs.com>2012-01-17 05:02:19 +0000
commit1d69510295bae9ee87d810cd9c9f8ce716e9c847 (patch)
treed4493f9b3031df6635e39159c659b11ee77626b4
parent223102db50c00b931bd40e3e9af0b407d345517d (diff)
import initial cut at rpki.gui.routeview app
svn path=/branches/tk161/; revision=4159
-rw-r--r--rpkid/Makefile.in5
-rw-r--r--rpkid/portal-gui/scripts/rpkigui-import-routes.py62
-rw-r--r--rpkid/portal-gui/settings.py.in3
-rw-r--r--rpkid/rpki/gui/app/templates/rpkigui/routes_view.html27
-rw-r--r--rpkid/rpki/gui/app/urls.py1
-rw-r--r--rpkid/rpki/gui/app/views.py31
-rw-r--r--rpkid/rpki/gui/routeview/__init__.py0
-rw-r--r--rpkid/rpki/gui/routeview/models.py68
-rw-r--r--rpkid/setup.py2
9 files changed, 196 insertions, 3 deletions
diff --git a/rpkid/Makefile.in b/rpkid/Makefile.in
index ff035f17..5c83dae7 100644
--- a/rpkid/Makefile.in
+++ b/rpkid/Makefile.in
@@ -44,7 +44,7 @@ POW_SO = rpki/POW/_POW.so
SCRIPTS = rpki-sql-backup rpki-sql-setup rpki-start-servers irbe_cli irdbd myrpki \
pubd rootd rpkic rpkid portal-gui/scripts/rpkigui-load-csv \
portal-gui/scripts/rpkigui-add-user portal-gui/scripts/rpkigui-response \
- portal-gui/scripts/rpkigui-rcynic
+ portal-gui/scripts/rpkigui-rcynic portal-gui/scripts/rpkigui-import-routes
AUX_SCRIPTS =
@@ -252,6 +252,9 @@ portal-gui/scripts/rpkigui-rcynic: portal-gui/scripts/rpkigui-rcynic.py
portal-gui/scripts/rpkigui-response: portal-gui/scripts/rpkigui-response.py
${COMPILE_DJANGO}
+portal-gui/scripts/rpkigui-import-routes: portal-gui/scripts/rpkigui-import-routes.py
+ ${COMPILE_DJANGO}
+
portal-gui/apache/rpki.wsgi: ${srcdir}/portal-gui/apache/rpki.wsgi.in
${COMPILE_DJANGO}
diff --git a/rpkid/portal-gui/scripts/rpkigui-import-routes.py b/rpkid/portal-gui/scripts/rpkigui-import-routes.py
new file mode 100644
index 00000000..dab4f4b6
--- /dev/null
+++ b/rpkid/portal-gui/scripts/rpkigui-import-routes.py
@@ -0,0 +1,62 @@
+import sys, itertools, re
+
+from django.db import transaction
+
+from rpki.gui.routeview import models
+from rpki.resource_set import resource_range_ipv4, resource_range_ipv6
+
+f = open(sys.argv[1])
+
+prefixes = {}
+
+ip_re = re.compile(r'^[0-9a-fA-F:.]+/\d{1,3}$')
+
+class InvalidPrefix(Exception):
+ pass
+
+for row in itertools.islice(f, 5, None):
+ try:
+ cols = row.split()
+
+ prefix = cols[1]
+
+ # validate the prefix since the "sh ip bgp" output is sometimes corrupt
+ # by no space between the prefix and the next hop IP address.
+ if not ip_re.match(prefix):
+ raise InvalidPrefix(prefix)
+
+ # index -1 is i/e/? for igp/egp
+ origin_as = cols[-2]
+
+ # skip AS_SETs
+ if origin_as[0] == '{':
+ continue
+
+ asns = prefixes.get(prefix)
+ if not asns:
+ asns = set()
+ prefixes[prefix] = asns
+ asns.add(int(origin_as))
+
+ #print 'prefix=%s asns=%s' % (prefix, asns)
+ except InvalidPrefix, e:
+ print >>sys.stderr, 'skipping bad entry: ' + row,
+ print >>sys.stderr, e
+
+f.close()
+
+@transaction.commit_on_success
+def commit():
+ print 'Deleting rows from table...'
+ models.RouteOrigin.objects.all().delete()
+
+ for prefix, asns in prefixes.iteritems():
+ family = 6 if ':' in prefix else 4
+ cls = resource_range_ipv6 if family == 6 else resource_range_ipv4
+ rng = cls.parse_str(prefix)
+
+ for asn in asns:
+ print 'Creating row for prefix=%s asn=%d' % (prefix, asn)
+ models.RouteOrigin.objects.create(prefix_min=rng.min, prefix_max=rng.max, family=family, asn=asn)
+
+commit()
diff --git a/rpkid/portal-gui/settings.py.in b/rpkid/portal-gui/settings.py.in
index 39080453..22c92b74 100644
--- a/rpkid/portal-gui/settings.py.in
+++ b/rpkid/portal-gui/settings.py.in
@@ -74,9 +74,10 @@ INSTALLED_APPS = (
'django.contrib.admindocs',
'django.contrib.contenttypes',
'django.contrib.sessions',
+ 'rpki.irdb',
'rpki.gui.app',
'rpki.gui.cacheview',
- 'rpki.irdb'
+ 'rpki.gui.routeview',
)
TEMPLATE_CONTEXT_PROCESSORS = (
diff --git a/rpkid/rpki/gui/app/templates/rpkigui/routes_view.html b/rpkid/rpki/gui/app/templates/rpkigui/routes_view.html
new file mode 100644
index 00000000..4ff59355
--- /dev/null
+++ b/rpkid/rpki/gui/app/templates/rpkigui/routes_view.html
@@ -0,0 +1,27 @@
+{% extends "rpkigui/app_base.html" %}
+
+{% block content %}
+
+<div class='page-header'>
+ </h1>Route Views</h1>
+</div>
+
+<p>
+This view shows currently advertised routes for the prefixes listed in resource certs received from RPKI parents.
+
+<table class='zebra-striped'>
+ <tr>
+ <th>Prefix</th>
+ <th>AS</th>
+ </tr>
+ {% for r in routes %}
+ <tr>
+ <td>{{ r.get_prefix_display }}</td>
+ <td>{{ r.asn }}</td>
+ </tr>
+ {% endfor %}
+</table>
+
+{% endblock %}
+
+<!-- vim: set sw=2: -->
diff --git a/rpkid/rpki/gui/app/urls.py b/rpkid/rpki/gui/app/urls.py
index d428b031..bb7da0b4 100644
--- a/rpkid/rpki/gui/app/urls.py
+++ b/rpkid/rpki/gui/app/urls.py
@@ -50,6 +50,7 @@ urlpatterns = patterns('',
(r'^roareq/$', views.roa_request_list),
(r'^roareq/(?P<pk>\d+)$', views.roa_request_view),
(r'^roareq/(?P<pk>\d+)/delete$', views.roa_request_delete_view),
+ (r'^routes/$', views.route_view),
(r'^demo/down/asns/(?P<self_handle>[^/]+)$', views.download_asns),
(r'^demo/down/prefixes/(?P<self_handle>[^/]+)$', views.download_prefixes),
(r'^demo/down/roas/(?P<self_handle>[^/]+)$', views.download_roas),
diff --git a/rpkid/rpki/gui/app/views.py b/rpkid/rpki/gui/app/views.py
index 014a13a3..3ffbccfb 100644
--- a/rpkid/rpki/gui/app/views.py
+++ b/rpkid/rpki/gui/app/views.py
@@ -35,6 +35,9 @@ from django.core.urlresolvers import reverse
from rpki.gui.app import models, forms, glue, misc, AllocationTree, settings
from rpki.gui.app.asnset import asnset
+import rpki.gui.cacheview.models
+import rpki.gui.routeview.models
+
debug = False
def my_login_required(f):
@@ -901,4 +904,32 @@ def destroy_handle(request, handle):
return render('rpkigui/destroy_handle_form.html', { 'form': form ,
'handle': handle }, request)
+@handle_required
+def route_view(request):
+ """
+ Display a list of global routing table entries which match resources listed
+ in received certificates.
+ """
+
+ handle = request.session['handle']
+ log = request.META['wsgi.errors']
+
+ routes = []
+ for p in models.AddressRange.objects.filter(from_cert__parent__in=handle.parents.all()):
+ r = p.as_resource_range()
+ qs = rpki.gui.routeview.models.RouteOrigin.objects.filter(prefix_min__gte=r.min, prefix_max__lte=r.max)
+ for obj in qs:
+ # determine the validation status of each route
+ routes.append(obj)
+
+# status = 'Not Found'
+# status_id = 'notfound'
+#
+# roas = rpki.gui.cacheview.models.ROAPrefix.objects.filter()
+#
+# obj.status = status
+# obj.status_id = status_id
+
+ return render('rpkigui/routes_view.html', { 'routes': routes }, request)
+
# vim:sw=4 ts=8 expandtab
diff --git a/rpkid/rpki/gui/routeview/__init__.py b/rpkid/rpki/gui/routeview/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/rpkid/rpki/gui/routeview/__init__.py
diff --git a/rpkid/rpki/gui/routeview/models.py b/rpkid/rpki/gui/routeview/models.py
new file mode 100644
index 00000000..411f4876
--- /dev/null
+++ b/rpkid/rpki/gui/routeview/models.py
@@ -0,0 +1,68 @@
+import binascii
+
+from django.db import models
+
+import rpki
+import rpki.resource_set
+import rpki.ipaddrs
+
+class PositiveHugeIntegerField(models.Field):
+
+ description = "Represents a 128-bit unsigned integer."
+
+ __metaclass__ = models.SubfieldBase
+
+ def db_type(self, connection):
+ if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
+ return 'binary(16)'
+ return 'blob'
+
+ def to_python(self, value):
+ if isinstance(value, int):
+ return long(value)
+ if isinstance(value, long):
+ return value
+ return long(binascii.hexlify(value), 16)
+
+ def get_db_prep_value(self, value, connection, prepared=False):
+ return binascii.unhexlify('%032x' % value)
+
+class RouteOrigin(models.Model):
+
+ asn = models.PositiveIntegerField(help_text='origin AS', db_index=True)
+ family = models.PositiveSmallIntegerField(help_text='IP version')
+
+ # address stored as unsigned integer to faciliate lookups
+ prefix_min = PositiveHugeIntegerField(db_index=True)
+ prefix_max = PositiveHugeIntegerField(db_index=True)
+
+ def as_range(self):
+ """
+ Returns the prefix as a rpki.resource_set.resource_range_ip object.
+ """
+ cls = rpki.resource_set.resource_range_ipv4 if self.family == 4 else rpki.resource_set.resource_range_ipv6
+ ipcls = rpki.ipaddrs.v4addr if self.family == 4 else rpki.ipaddrs.v6addr
+ return cls(ipcls(self.prefix_min), ipcls(self.prefix_max))
+
+ def get_prefix_display(self):
+ """
+ Returns a string version of the prefix in the routing entry.
+ """
+ return str(self.as_range())
+
+ def prefixlen(self):
+ """
+ Returns the prefix length for this route object.
+ """
+ return self.as_range().prefixlen()
+
+ def __unicode__(self):
+ return u"AS%d's route origin for %s" % (self.asn, self.get_prefix_display())
+
+ class Meta:
+ # sort order reflects what "sh ip bgp" outputs
+ ordering = ( 'prefix_min', 'prefix_max', 'asn' )
+
+ unique_together = ('asn', 'prefix_min', 'prefix_max')
+
+# vim:sw=4 ts=8 expandtab
diff --git a/rpkid/setup.py b/rpkid/setup.py
index 75d6069c..ffa0590c 100644
--- a/rpkid/setup.py
+++ b/rpkid/setup.py
@@ -63,7 +63,7 @@ setup(name = "rpkitoolkit",
description = "RPKI Toolkit",
license = "BSD",
url = "http://www.rpki.net/",
- packages = ["rpki", "rpki.POW", "rpki.gui", "rpki.gui.app", "rpki.gui.cacheview" ],
+ packages = ["rpki", "rpki.POW", "rpki.gui", "rpki.gui.app", "rpki.gui.cacheview", "rpki.gui.routeview" ],
ext_modules = [pow],
package_data = { 'rpki.gui.app' : ['templates/*.html', 'templates/*/*.html'],
'rpki.gui.cacheview' : [ 'templates/*/*.html' ] },