diff options
author | Rob Austein <sra@hactrn.net> | 2014-08-12 15:35:45 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2014-08-12 15:35:45 +0000 |
commit | 507af6c1abba20a65450e16ef13fe09a398b8f91 (patch) | |
tree | 111439eeb1f6263ffd77ace5e1e16e1e5b20182d | |
parent | b01cefe6bcfeeaea58b1dc54caedb53aa6952150 (diff) |
HTTP publication of RRDP.
svn path=/branches/tk705/; revision=5918
-rw-r--r-- | ca/rpki-confgen.xml | 28 | ||||
-rwxr-xr-x | ca/rpkigui-apache-conf-gen | 64 | ||||
-rw-r--r-- | h/rpki/sk_roa.h | 2 | ||||
-rwxr-xr-x | potpourri/rrdp-fetch.py | 68 | ||||
-rwxr-xr-x | potpourri/rrdp-test-tool | 2 | ||||
-rw-r--r-- | rpki/pubd.py | 28 | ||||
-rw-r--r-- | rpki/sql_schemas.py | 2 |
7 files changed, 166 insertions, 28 deletions
diff --git a/ca/rpki-confgen.xml b/ca/rpki-confgen.xml index 13c2c798..1928c2db 100644 --- a/ca/rpki-confgen.xml +++ b/ca/rpki-confgen.xml @@ -186,6 +186,20 @@ </doc> </option> + <option name = "rrdp_publication_base_directory" + value = "${autoconf::datarootdir}/rpki/rrdp-publication"> + <doc> + Root of local directory tree where pubd should write out RRDP + files. You need to configure this, and the configuration + should match up with the directory where you point the web + server (usually Apache) that serves the RRDP files. Neither + pubd nor Apache much cares //where// you tell it to put this + stuff, the important thing is that all the URIs match up so + that relying parties can find and verify rpkid's published + outputs. + </doc> + </option> + <option name = "publication_rsync_module" value = "rpki"> <doc> @@ -554,6 +568,20 @@ </doc> </option> + <option name = "rrdp-publication-base" + value = "${myrpki::rrdp_publication_base_directory}"> + <doc> + Root of local directory tree where pubd should write out RRDP + files. You need to configure this, and the configuration + should match up with the directory where you point the web + server (usually Apache) that serves the RRDP files. Neither + pubd nor Apache much cares //where// you tell it to put this + stuff, the important thing is that all the URIs match up so + that relying parties can find and verify rpkid's published + outputs. + </doc> + </option> + <option name = "server-host" value = "${myrpki::pubd_server_host}"> <doc> diff --git a/ca/rpkigui-apache-conf-gen b/ca/rpkigui-apache-conf-gen index 0f56342f..8ab8819a 100755 --- a/ca/rpkigui-apache-conf-gen +++ b/ca/rpkigui-apache-conf-gen @@ -29,6 +29,50 @@ import rpki.autoconf fqdn = socket.getfqdn() vhost_template = """\ + +# +# Stuff that should be visible with both HTTP and HTTPS is (now) +# outside the vhost block (see if this works properly...). +# + +# +# Allow access to the directory where rcynic-html writes +# its output files. +# +<Directory %(RCYNIC_HTML_DIR)s> +%(allow)s +</Directory> + +# +# Add alias pointing to rcynic-html's output files. +# +# If for some reason you need to change this, be careful to leave +# the trailing slash off the URL, otherwise /rcynic will be +# swallowed by the WSGIScriptAlias +# +Alias /rcynic %(RCYNIC_HTML_DIR)s/ + +# +# Allow access to the directory where pubd writes RRDP files. +# +<Directory %(datarootdir)s/rpki/rrdp-publication/> +%(allow)s +</Directory> + +# +# Add alias pointing to pubd's RRD output files. +# +Alias /rrdp %(datarootdir)s/rpki/rrdp-publication/ + +# +# RRDP "notification" file needs a short expiration: this is +# a critical part of how RRDP interacts with HTTP caching. +# +<LocationMatch ^/rrdp/updates[.]xml$> + ExpiresActive on + ExpiresDefault "access plus 5 minutes" +</LocationMatch> + # # By default, this configuration assumes that you use name-based # virtual hosting. If that's not what you want, you may need @@ -78,23 +122,6 @@ vhost_template = """\ Alias /site_media/ %(datarootdir)s/rpki/media/ # - # Allow access to the directory where rcynic-html writes - # its output files. - # - <Directory %(RCYNIC_HTML_DIR)s> -%(allow)s - </Directory> - - # - # Add alias pointing to rcynic-html's output files. - # - # If for some reason you need to change this, be careful to leave - # the trailing slash off the URL, otherwise /rcynic will be - # swallowed by the WSGIScriptAlias - # - Alias /rcynic %(RCYNIC_HTML_DIR)s/ - - # # Redirect to the GUI dashboard when someone hits the bare vhost. # RedirectMatch ^/$ /rpki/ @@ -102,7 +129,7 @@ vhost_template = """\ # # Enable HTTPS # - SSLEngine on + SSLEngine on # # Specify HTTPS server certificate and key files for this virtual host. @@ -402,6 +429,7 @@ class Debian(Platform): def enable(self): self.run("a2enmod", "ssl") + self.run("a2enmod", "expires") self.run("a2ensite", "rpki") # # In light of BREACH and CRIME attacks, mod_deflate is looking diff --git a/h/rpki/sk_roa.h b/h/rpki/sk_roa.h index 13036955..7423f8ff 100644 --- a/h/rpki/sk_roa.h +++ b/h/rpki/sk_roa.h @@ -1,6 +1,6 @@ /* * Automatically generated, do not edit. - * Generator $Id: defstack.py 4878 2012-11-15 22:13:53Z sra $ + * Generator $Id: defstack.py 5784 2014-04-10 22:56:47Z sra $ */ #ifndef __RPKI_ROA_H__DEFSTACK_H__ diff --git a/potpourri/rrdp-fetch.py b/potpourri/rrdp-fetch.py new file mode 100755 index 00000000..aa5b762b --- /dev/null +++ b/potpourri/rrdp-fetch.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# $Id$ +# +# Copyright (C) 2014 Dragon Research Labs ("DRL") +# +# 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 DRL DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL DRL 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. + +""" +Fetch an RRDP notifcation file and follow all the links. Should be +merged into rrdp-test-tool eventually, but one thing at a time. +""" + +from urllib2 import urlopen +from lxml.etree import ElementTree, XML +from socket import getfqdn +from rpki.x509 import sha256 +from rpki.relaxng import rrdp +from urlparse import urlparse +from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter + +class BadHash(Exception): + "Calculated hash value doesn't match expected hash value." + +def fetch(elt): + uri = elt.get("uri") + hash = elt.get("hash") + print "Fetching", uri + + text = urlopen(uri).read() + h = sha256(text).encode("hex") + if h != hash: + raise BadHash("Bad hash for %s: expected %s got %s" % (uri, hash, h)) + + xml = XML(text) + rrdp.schema.assertValid(xml) + + u = urlparse(uri) + fn = u.netloc + u.path + + return elt, xml, fn + +parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter) +parser.add_argument("uri", nargs = "?", + default = "http://" + getfqdn() + "/rrdp/updates.xml", + help = "RRDP notification file to fetch") +args = parser.parse_args() + +updates = ElementTree(file = urlopen(args.uri)) +rrdp.schema.assertValid(updates) + +snapshot = fetch(updates.find(rrdp.xmlns + "snapshot")) + +deltas = [fetch(elt) for elt in updates.findall(rrdp.xmlns + "delta")] + +print updates +print snapshot +for delta in deltas: + print delta diff --git a/potpourri/rrdp-test-tool b/potpourri/rrdp-test-tool index 9bdb53b5..b4dc65da 100755 --- a/potpourri/rrdp-test-tool +++ b/potpourri/rrdp-test-tool @@ -1,7 +1,7 @@ #!/usr/bin/env python # $Id$ # -# Copyright (C) 2013 Dragon Research Labs ("DRL") +# Copyright (C) 2014 Dragon Research Labs ("DRL") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above diff --git a/rpki/pubd.py b/rpki/pubd.py index ae2265bf..b6788ebd 100644 --- a/rpki/pubd.py +++ b/rpki/pubd.py @@ -125,9 +125,11 @@ class main(object): self.publication_base = self.cfg.get("publication-base", "publication/") - self.rrdp_uri_base = self.cfg.get("rrdp-uri-base", "http://%s/" % socket.getfqdn()) + self.rrdp_uri_base = self.cfg.get("rrdp-uri-base", + "http://%s/rrdp/" % socket.getfqdn()) self.rrdp_expiration_interval = rpki.sundial.timedelta.parse(self.cfg.get("rrdp-expiration-interval", "6h")) - self.rrdp_publication_base = self.cfg.get("rrdp-publication-base", "rrdp-publication/") + self.rrdp_publication_base = self.cfg.get("rrdp-publication-base", + "rrdp-publication/") self.session = session_obj.fetch(self) @@ -138,6 +140,10 @@ class main(object): ("/client/", self.client_handler))) + def rrdp_filename_to_uri(self, fn): + return "%s/%s" % (self.rrdp_uri_base.rstrip("/"), fn) + + def control_handler(self, query, path, cb): """ Process one PDU from the IRBE. @@ -346,12 +352,20 @@ class session_obj(rpki.sql.sql_persistent): self.hash = rpki.x509.sha256(self.snapshot).encode("hex") self.sql_store() + @property + def snapshot_fn(self): + return "%s/snapshot/%s.xml" % (self.uuid, self.serial) + + @property + def notification_fn(self): + return "updates.xml" + def write_snapshot(self): """ Write current session snapshot to disk. """ - self.write_rrdp_file("snapshot/%s/%s.xml" % (self.uuid, self.serial), self.snapshot) + self.write_rrdp_file(self.snapshot_fn, self.snapshot) def write_deltas(self): """ @@ -371,16 +385,16 @@ class session_obj(rpki.sql.sql_persistent): session_id = self.uuid, serial = str(self.serial)) SubElement(xml, rrdp_xmlns + "snapshot", - uri = "%s/snapshot/%s/%d.xml" % (self.gctx.rrdp_uri_base, self.uuid, self.serial), + uri = self.gctx.rrdp_filename_to_uri(self.snapshot_fn), hash = self.hash) for delta in self.deltas: se = SubElement(xml, rrdp_xmlns + "delta", to = str(delta.serial), - uri = "%s/%s" % (self.gctx.rrdp_uri_base, delta.fn), + uri = self.gctx.rrdp_filename_to_uri(delta.fn), hash = delta.hash) se.set("from", str(delta.serial - 1)) rpki.relaxng.rrdp.assertValid(xml) - self.write_rrdp_file("notification/%s.xml" % self.uuid, + self.write_rrdp_file(self.notification_fn, ElementToString(xml, pretty_print = True), overwrite = True) @@ -406,7 +420,7 @@ class delta_obj(rpki.sql.sql_persistent): @property def fn(self): - return "deltas/%s/%s-%s.xml" % (self.session.uuid, self.serial - 1, self.serial) + return "%s/deltas/%s-%s.xml" % (self.session.uuid, self.serial - 1, self.serial) @classmethod def create(cls, session): diff --git a/rpki/sql_schemas.py b/rpki/sql_schemas.py index 38ce8fc8..fc262f12 100644 --- a/rpki/sql_schemas.py +++ b/rpki/sql_schemas.py @@ -245,7 +245,7 @@ CREATE TABLE ee_cert ( ## @var pubd ## SQL schema pubd -pubd = '''-- $Id: pubd.sql 5901 2014-07-17 21:57:36Z sra $ +pubd = '''-- $Id: pubd.sql 5914 2014-08-06 22:52:28Z sra $ -- Copyright (C) 2012--2014 Dragon Research Labs ("DRL") -- Portions copyright (C) 2009--2010 Internet Systems Consortium ("ISC") |