diff options
author | Michael Elkins <melkins@tislabs.com> | 2012-01-17 05:02:19 +0000 |
---|---|---|
committer | Michael Elkins <melkins@tislabs.com> | 2012-01-17 05:02:19 +0000 |
commit | 1d69510295bae9ee87d810cd9c9f8ce716e9c847 (patch) | |
tree | d4493f9b3031df6635e39159c659b11ee77626b4 | |
parent | 223102db50c00b931bd40e3e9af0b407d345517d (diff) |
import initial cut at rpki.gui.routeview app
svn path=/branches/tk161/; revision=4159
-rw-r--r-- | rpkid/Makefile.in | 5 | ||||
-rw-r--r-- | rpkid/portal-gui/scripts/rpkigui-import-routes.py | 62 | ||||
-rw-r--r-- | rpkid/portal-gui/settings.py.in | 3 | ||||
-rw-r--r-- | rpkid/rpki/gui/app/templates/rpkigui/routes_view.html | 27 | ||||
-rw-r--r-- | rpkid/rpki/gui/app/urls.py | 1 | ||||
-rw-r--r-- | rpkid/rpki/gui/app/views.py | 31 | ||||
-rw-r--r-- | rpkid/rpki/gui/routeview/__init__.py | 0 | ||||
-rw-r--r-- | rpkid/rpki/gui/routeview/models.py | 68 | ||||
-rw-r--r-- | rpkid/setup.py | 2 |
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' ] }, |