aboutsummaryrefslogtreecommitdiff
path: root/rpkid/rpki/gui/app/glue.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid/rpki/gui/app/glue.py')
-rw-r--r--rpkid/rpki/gui/app/glue.py506
1 files changed, 68 insertions, 438 deletions
diff --git a/rpkid/rpki/gui/app/glue.py b/rpkid/rpki/gui/app/glue.py
index 687af268..7de1a9e5 100644
--- a/rpkid/rpki/gui/app/glue.py
+++ b/rpkid/rpki/gui/app/glue.py
@@ -1,125 +1,48 @@
-# $Id$
-"""
-Copyright (C) 2010, 2011 SPARTA, Inc. dba Cobham Analytic Solutions
+# Copyright (C) 2010, 2011 SPARTA, Inc. dba Cobham Analytic Solutions
+# Copyright (C) 2012 SPARTA, Inc. a Parsons Company
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+"""
+This file contains code that interfaces between the django views implementing
+the portal gui and the rpki.* modules.
-THE SOFTWARE IS PROVIDED "AS IS" AND SPARTA DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS. IN NO EVENT SHALL SPARTA BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
"""
from __future__ import with_statement
-import os, os.path, csv, shutil, stat, sys
-from datetime import datetime, timedelta
+__version__ = '$Id$'
-from django.db.models import F
+from datetime import datetime
-import rpki, rpki.async, rpki.http, rpki.x509, rpki.left_right, rpki.myrpki
-import rpki.publication
+from rpki.resource_set import (resource_set_as, resource_set_ipv4,
+ resource_set_ipv6, resource_range_ipv4,
+ resource_range_ipv6)
+from rpki.left_right import list_received_resources_elt
+from rpki.irdb.zookeeper import Zookeeper
from rpki.gui.app import models, settings
-def confpath(*handle):
- """
- Return the absolute pathname to the configuration directory for
- the given resource handle. If additional arguments are given, they
- are taken to mean files/subdirectories.
- """
- argv = [ settings.CONFDIR ]
- argv.extend(handle)
- return os.path.join(*argv)
-
-def read_file_from_handle(handle, fname):
- """read a filename relative to the directory for the given resource handle. returns
- a tuple of (content, mtime)"""
- with open(confpath(handle, fname), 'r') as fp:
- data = fp.read()
- mtime = os.fstat(fp.fileno())[stat.ST_MTIME]
- return data, mtime
-
-read_identity = lambda h: read_file_from_handle(h, 'entitydb/identity.xml')[0]
-
-def output_asns(path, handle):
- '''Write out csv file containing asns delegated to my children.'''
- qs = models.Asn.objects.filter(lo=F('hi'), allocated__in=handle.children.all())
- w = rpki.myrpki.csv_writer(path)
- w.writerows([asn.allocated.handle, asn.lo] for asn in qs)
- w.close()
-
-def output_prefixes(path, handle):
- '''Write out csv file containing prefixes delegated to my children.'''
- qs = models.AddressRange.objects.filter(allocated__in=handle.children.all())
- w = rpki.myrpki.csv_writer(path)
- w.writerows([p.allocated.handle, p.as_resource_range()] for p in qs)
- w.close()
-
-def output_roas(path, handle):
- '''Write out csv file containing my roas.'''
- qs = models.RoaRequest.objects.filter(roa__in=handle.roas.all())
- w = rpki.myrpki.csv_writer(path)
- w.writerows([req.as_roa_prefix(), req.roa.asn,
- '%s-group-%d' % (handle.handle, req.roa.pk)] for req in qs)
- w.close()
-
-def qualify_path(pfx, fname):
- """Ensure 'path' is an absolute filename."""
- return fname if fname.startswith('/') else os.path.join(pfx, fname)
-
-def build_rpkid_caller(cfg, verbose=False):
- """
- Returns a function suitable for calling rpkid using the
- configuration information specified in the rpki.config.parser
- object.
- """
- bpki_servers_dir = cfg.get("bpki_servers_directory")
- if not bpki_servers_dir.startswith('/'):
- bpki_servers_dir = confpath(cfg.get('handle'), bpki_servers_dir)
-
- bpki_servers = rpki.myrpki.CA(cfg.filename, bpki_servers_dir)
- rpkid_base = "http://%s:%s/" % (cfg.get("rpkid_server_host"), cfg.get("rpkid_server_port"))
-
- return rpki.async.sync_wrapper(rpki.http.caller(
- proto = rpki.left_right,
- client_key = rpki.x509.RSA(PEM_file = bpki_servers.dir + "/irbe.key"),
- client_cert = rpki.x509.X509(PEM_file = bpki_servers.dir + "/irbe.cer"),
- server_ta = rpki.x509.X509(PEM_file = bpki_servers.cer),
- server_cert = rpki.x509.X509(PEM_file = bpki_servers.dir + "/rpkid.cer"),
- url = rpkid_base + "left-right",
- debug = verbose))
-
-def build_pubd_caller(cfg):
- bpki_servers_dir = cfg.get("bpki_servers_directory")
- if not bpki_servers_dir.startswith('/'):
- bpki_servers_dir = confpath(cfg.get('handle'), bpki_servers_dir)
-
- bpki_servers = rpki.myrpki.CA(cfg.filename, bpki_servers_dir)
- pubd_base = "http://%s:%s/" % (cfg.get("pubd_server_host"), cfg.get("pubd_server_port"))
-
- return rpki.async.sync_wrapper(rpki.http.caller(
- proto = rpki.publication,
- client_key = rpki.x509.RSA( PEM_file = bpki_servers.dir + "/irbe.key"),
- client_cert = rpki.x509.X509(PEM_file = bpki_servers.dir + "/irbe.cer"),
- server_ta = rpki.x509.X509(PEM_file = bpki_servers.cer),
- server_cert = rpki.x509.X509(PEM_file = bpki_servers.dir + "/pubd.cer"),
- url = pubd_base + "control"))
def ghostbuster_to_vcard(gbr):
- """
- Convert a Ghostbuster object into a vCard object.
- """
+ """Convert a GhostbusterRequest object into a vCard object."""
import vobject
vcard = vobject.vCard()
- vcard.add('N').value = vobject.vcard.Name(family=gbr.family_name, given=gbr.given_name)
+ vcard.add('N').value = vobject.vcard.Name(family=gbr.family_name,
+ given=gbr.given_name)
- adr_fields = [ 'box', 'extended', 'street', 'city', 'region', 'code', 'country' ]
+ adr_fields = ['box', 'extended', 'street', 'city', 'region', 'code',
+ 'country']
adr_dict = dict((f, getattr(gbr, f, '')) for f in adr_fields)
if any(adr_dict.itervalues()):
vcard.add('ADR').value = vobject.vcard.Address(**adr_dict)
@@ -128,185 +51,64 @@ def ghostbuster_to_vcard(gbr):
# the ORG type is a sequence of organization unit names, so
# transform the org name into a tuple before stuffing into the
# vCard object
- attrs = [ ('FN', 'full_name', None),
- ('TEL', 'telephone', None),
- ('ORG', 'organization', lambda x: (x,)),
- ('EMAIL', 'email_address', None) ]
+ attrs = [('FN', 'full_name', None),
+ ('TEL', 'telephone', None),
+ ('ORG', 'organization', lambda x: (x,)),
+ ('EMAIL', 'email_address', None)]
for vtype, field, transform in attrs:
v = getattr(gbr, field)
if v:
vcard.add(vtype).value = transform(v) if transform else v
return vcard.serialize()
-def qualify_path(pfx, fname):
- """
- Ensure 'path' is an absolute filename.
- """
- return fname if fname.startswith('/') else os.path.join(pfx, fname)
-
-def configure_resources(log, handle):
- """
- This function should be called when resources for this resource
- holder have changed. It updates IRDB and notifies rpkid to
- immediately process the changes, rather than waiting for the cron
- job to run.
- For backwards compatability (and backups), it also writes the csv
- files for use with the myrpki.py command line script.
+def list_received_resources(log, conf):
"""
+ Query rpkid for this resource handle's received resources.
- path = confpath(handle.handle)
- cfg = rpki.config.parser(os.path.join(path, 'rpki.conf'), 'myrpki')
-
- output_asns(qualify_path(path, cfg.get('asn_csv')), handle)
- output_prefixes(qualify_path(path, cfg.get('prefix_csv')), handle)
- output_roas(qualify_path(path, cfg.get('roa_csv')), handle)
-
- roa_requests = []
- for roa in handle.roas.all():
- v4 = rpki.resource_set.roa_prefix_set_ipv4()
- v6 = rpki.resource_set.roa_prefix_set_ipv6()
- for req in roa.from_roa_request.all():
- pfx = req.as_roa_prefix()
- if isinstance(pfx, rpki.resource_set.roa_prefix_ipv4):
- v4.append(pfx)
- else:
- v6.append(pfx)
- roa_requests.append((roa.asn, v4, v6))
-
- children = []
- for child in handle.children.all():
- asns = rpki.resource_set.resource_set_as([a.as_resource_range() for a in child.asn.all()])
-
- v4 = rpki.resource_set.resource_set_ipv4()
- v6 = rpki.resource_set.resource_set_ipv6()
- for pfx in child.address_range.all():
- rng = pfx.as_resource_range()
- if isinstance(rng, rpki.resource_set.resource_range_ipv4):
- v4.append(rng)
- else:
- v6.append(rng)
-
- # convert from datetime.datetime to rpki.sundial.datetime
- valid_until = rpki.sundial.datetime.fromdatetime(child.valid_until)
- children.append((child.handle, asns, v4, v6, valid_until))
-
- ghostbusters = []
- for gbr in handle.ghostbusters.all():
- vcard = ghostbuster_to_vcard(gbr)
- parent_set = gbr.parent.all()
- if parent_set:
- for p in parent_set:
- ghostbusters.append((p, vcard))
- else:
- ghostbusters.append((None, vcard))
+ The semantics are to clear the entire table and populate with the list of
+ certs received. Other models should not reference the table directly with
+ foreign keys.
- # for hosted handles, get the config for the irdbd/rpkid host
- if handle.host:
- cfg = rpki.config.parser(confpath(handle.host.handle, 'rpki.conf'), 'myrpki')
-
- irdb = rpki.myrpki.IRDB(cfg)
- irdb.update(handle, roa_requests, children, ghostbusters)
- irdb.close()
+ """
- # contact rpkid to request immediate update
- call_rpkid = build_rpkid_caller(cfg)
- call_rpkid(rpki.left_right.self_elt.make_pdu(action='set', self_handle=handle.handle, run_now=True))
+ z = Zookeeper(handle=conf.handle)
+ pdus = z.call_rpkid(list_received_resources_elt.make_pdu(self_handle=conf.handle))
-def list_received_resources(log, conf):
- "Query rpkid for this resource handle's children and received resources."
-
- # if this handle is hosted, get the cfg for the host
- rpki_conf = conf.host if conf.host else conf
- cfg = rpki.config.parser(confpath(rpki_conf.handle, 'rpki.conf'), 'myrpki')
- call_rpkid = build_rpkid_caller(cfg)
- pdus = call_rpkid(rpki.left_right.list_received_resources_elt.make_pdu(self_handle=conf.handle),
- rpki.left_right.child_elt.make_pdu(action="list", self_handle=conf.handle),
- rpki.left_right.parent_elt.make_pdu(action="list", self_handle=conf.handle))
+ models.ResourceCert.objects.filter(parent__issuer=conf).delete()
for pdu in pdus:
- if isinstance(pdu, rpki.left_right.child_elt):
- # have we seen this child before?
- child_set = conf.children.filter(handle=pdu.child_handle)
- if not child_set:
- # default to 1 year. no easy way to query irdb for the
- # current value.
- valid_until = datetime.now() + timedelta(days=365)
- child = models.Child(conf=conf, handle=pdu.child_handle,
- valid_until=valid_until)
- child.save()
-
- elif isinstance(pdu, rpki.left_right.parent_elt):
- # have we seen this parent before?
- parent_set = conf.parents.filter(handle=pdu.parent_handle)
- if not parent_set:
- parent = models.Parent(conf=conf, handle=pdu.parent_handle)
- parent.save()
-
- elif isinstance(pdu, rpki.left_right.list_received_resources_elt):
-
- # have we seen this parent before?
- parent_set = conf.parents.filter(handle=pdu.parent_handle)
- if not parent_set:
- parent = models.Parent(conf=conf, handle=pdu.parent_handle)
- parent.save()
- else:
- parent = parent_set[0]
+ if isinstance(pdu, list_received_resources_elt):
+ parent = models.Parent.objects.get(issuer=conf,
+ handle=pdu.parent_handle)
not_before = datetime.strptime(pdu.notBefore, "%Y-%m-%dT%H:%M:%SZ")
not_after = datetime.strptime(pdu.notAfter, "%Y-%m-%dT%H:%M:%SZ")
- #print >>log, 'uri: %s, not before: %s, not after: %s' % (pdu.uri, not_before, not_after)
+ cert = models.ResourceCert.objects.create(parent=parent,
+ not_before=not_before, not_after=not_after,
+ uri=pdu.uri)
- # have we seen this resource cert before?
- cert_set = parent.resources.filter(uri=pdu.uri)
- if cert_set.count() == 0:
- cert = models.ResourceCert(uri=pdu.uri, parent=parent,
- not_before=not_before, not_after=not_after)
- else:
- cert = cert_set[0]
- # update timestamps since it could have been modified
- cert.not_before = not_before
- cert.not_after = not_after
- cert.save()
+ for asn in resource_set_as(pdu.asn):
+ cert.asn_ranges.create(min=asn.min, max=asn.max)
- for asn in rpki.resource_set.resource_set_as(pdu.asn):
- # see if this resource is already part of the cert
- if cert.asn.filter(lo=asn.min, hi=asn.max).count() == 0:
- # ensure this range wasn't seen from another of our parents
- for v in models.Asn.objects.filter(lo=asn.min, hi=asn.max):
- # determine if resource is delegated from another parent
- if v.from_cert.filter(parent__in=conf.parents.all()).count():
- cert.asn.add(v)
- break
- else:
- cert.asn.create(lo=asn.min, hi=asn.max)
- cert.save()
+ for rng in resource_set_ipv4(pdu.ipv4):
+ print >>log, 'adding v4 address range: %s' % rng
+ cert.address_ranges.create(prefix_min=rng.min,
+ prefix_max=rng.max)
- # IPv4/6 - not separated in the django db
- def add_missing_address(addr_set):
- for ip in addr_set:
- lo=str(ip.min)
- hi=str(ip.max)
- if cert.address_range.filter(lo=lo, hi=hi).count() == 0:
- # ensure that this range wasn't previously seen from another of our parents
- for v in models.AddressRange.objects.filter(lo=lo, hi=hi):
- # determine if this resource is delegated from another parent as well
- if v.from_cert.filter(parent__in=conf.parents.all()).count():
- cert.address_range.add(v)
- break
- else:
- cert.address_range.create(lo=lo, hi=hi)
- cert.save()
+ for rng in resource_set_ipv6(pdu.ipv6):
+ cert.address_ranges_v6.create(prefix_min=rng.min,
+ prefix_max=rng.max)
+ else:
+ print >>log, "error: unexpected pdu from rpkid type=%s" % type(pdu)
- add_missing_address(rpki.resource_set.resource_set_ipv4(pdu.ipv4))
- add_missing_address(rpki.resource_set.resource_set_ipv6(pdu.ipv6))
def config_from_template(dest, a):
"""
- Create a new rpki.conf file from a generic template. Go line by
- line through the template and substitute directives from the
- dictionary 'a'.
+ Create a new rpki.conf file from a generic template. Go line by line
+ through the template and substitute directives from the dictionary 'a'.
+
"""
with open(dest, 'w') as f:
for r in open(settings.RPKI_CONF_TEMPLATE):
@@ -320,181 +122,9 @@ def config_from_template(dest, a):
else:
print >>f, r,
-class Myrpki(rpki.myrpki.main):
- """
- wrapper around rpki.myrpki.main to force the config file to what i want,
- and avoid cli arg parsing.
- """
- def __init__(self, handle):
- self.cfg_file = confpath(handle, 'rpki.conf')
- self.read_config()
-
-def configure_daemons(log, conf, m):
- if conf.host:
- m.configure_resources_main()
-
- host = Myrpki(conf.host.handle)
- host.do_configure_daemons(m.cfg.get('xml_filename'))
- else:
- m.do_configure_daemons('')
-
-def initialize_handle(log, handle, host, owner=None, commit=True):
- """
- Create a new Conf object for this user.
- """
- print >>log, "initializing new resource handle %s" % handle
-
- qs = models.Conf.objects.filter(handle=handle)
- if not qs:
- conf = models.Conf(handle=handle, host=host)
- conf.save()
- if owner:
- conf.owner.add(owner)
- else:
- conf = qs[0]
-
- # create the config directory if it doesn't already exist
- top = confpath(conf.handle)
- if not os.path.exists(top):
- os.makedirs(top)
-
- cfg_file = confpath(conf.handle, 'rpki.conf')
-
- # create rpki.conf file if it doesn't exist
- if not os.path.exists(cfg_file):
- print >>log, "generating rpki.conf for %s" % conf.handle
- config_from_template(cfg_file, { 'handle': conf.handle,
- 'configuration_directory': top, 'run_rpkid': 'false'})
-
- # create stub csv files
- for f in ('asns', 'prefixes', 'roas'):
- p = confpath(conf.handle, f + '.csv')
- if not os.path.exists(p):
- f = open(p, 'w')
- f.close()
-
- # load configuration for self
- m = Myrpki(conf.handle)
- m.do_initialize('')
-
- if commit:
- # run twice the first time to get bsc cert issued
- configure_daemons(log, conf, m)
- configure_daemons(log, conf, m)
-
- return conf, m
-
-def import_child(log, conf, child_handle, xml_file):
- """
- Import a child's identity.xml.
- """
- m = Myrpki(conf.handle)
- m.do_configure_child(xml_file)
- configure_daemons(log, conf, m)
-
-def import_parent(log, conf, parent_handle, xml_file):
- m = Myrpki(conf.handle)
- m.do_configure_parent(xml_file)
- configure_daemons(log, conf, m)
-
-def import_pubclient(log, conf, xml_file):
- m = Myrpki(conf.handle)
- m.do_configure_publication_client(xml_file)
- configure_daemons(log, conf, m)
-
-def import_repository(log, conf, xml_file):
- m = Myrpki(conf.handle)
- m.do_configure_repository(xml_file)
- configure_daemons(log, conf, m)
-
-def create_child(log, parent_conf, child_handle):
- """
- implements the child create wizard to create a new locally hosted child
- """
- child_conf, child = initialize_handle(log, handle=child_handle, host=parent_conf, commit=False)
-
- parent_handle = parent_conf.handle
- parent = Myrpki(parent_handle)
-
- child_identity_xml = os.path.join(child.cfg.get("entitydb_dir"), 'identity.xml')
- parent_response_xml = os.path.join(parent.cfg.get("entitydb_dir"), 'children', child_handle + '.xml')
- repo_req_xml = os.path.join(child.cfg.get('entitydb_dir'), 'repositories', parent_handle + '.xml')
- # XXX for now we assume the child is hosted by parent's pubd
- repo_resp_xml = os.path.join(parent.cfg.get('entitydb_dir'), 'pubclients', '%s.%s.xml' % (parent_handle, child_handle))
-
- parent.do_configure_child(child_identity_xml)
-
- child.do_configure_parent(parent_response_xml)
-
- parent.do_configure_publication_client(repo_req_xml)
-
- child.do_configure_repository(repo_resp_xml)
-
- # run twice the first time to get bsc cert issued
- sys.stdout = sys.stderr
- configure_daemons(log, child_conf, child)
- configure_daemons(log, child_conf, child)
-
-def destroy_handle(log, handle):
- conf = models.Conf.objects.get(handle=handle)
-
- cfg = rpki.config.parser(confpath(conf.host.handle, 'rpki.conf'), 'myrpki')
- call_rpkid = build_rpkid_caller(cfg)
- call_pubd = build_pubd_caller(cfg)
-
- # destroy the <self/> object and the <child/> object from the host/parent.
- rpkid_reply = call_rpkid(
- rpki.left_right.self_elt.make_pdu(action="destroy", self_handle=handle),
- rpki.left_right.child_elt.make_pdu(action="destroy", self_handle=conf.host.handle, child_handle=handle))
- if isinstance(rpkid_reply[0], rpki.left_right.report_error_elt):
- print >>log, "Error while calling pubd to delete client %s:" % handle
- print >>log, rpkid_reply[0]
-
- pubd_reply = call_pubd(rpki.publication.client_elt.make_pdu(action="destroy", client_handle=handle))
- if isinstance(pubd_reply[0], rpki.publication.report_error_elt):
- print >>log, "Error while calling pubd to delete client %s:" % handle
- print >>log, pubd_reply[0]
-
- conf.delete()
-
- shutil.remove(confpath(handle))
-
-def read_child_response(log, conf, child_handle):
- m = Myrpki(conf.handle)
- bname = child_handle + '.xml'
- return open(os.path.join(m.cfg.get('entitydb_dir'), 'children', bname)).read()
-
-def read_child_repo_response(log, conf, child_handle):
- """
- Return the XML file for the configure_publication_client response to the
- child.
-
- Note: the current model assumes the publication client is a child of this
- handle.
- """
-
- m = Myrpki(conf.handle)
- return open(os.path.join(m.cfg.get('entitydb_dir'), 'pubclients', '%s.%s.xml' % (conf.handle, child_handle))).read()
-
-def update_bpki(log, conf):
- m = Myrpki(conf.handle)
-
- # automatically runs configure_daemons when self-hosted
- # otherwise runs configure_resources
- m.do_update_bpki('')
-
- # when hosted, ship off to rpkid host
- if conf.host:
- configure_daemons(log, conf, m)
-
-def delete_child(log, conf, child_handle):
- m = Myrpki(conf.handle)
- m.do_delete_child(child_handle)
- configure_daemons(log, conf, m)
-
-def delete_parent(log, conf, parent_handle):
- m = Myrpki(conf.handle)
- m.do_delete_parent(parent_handle)
- configure_daemons(log, conf, m)
-
-# vim:sw=4 ts=8 expandtab
+def str_to_resource_range(prefix):
+ try:
+ r = resource_range_ipv4.parse_str(prefix)
+ except BadIPResource:
+ r = resource_range_ipv6.parse_str(prefix)
+ return r