aboutsummaryrefslogtreecommitdiff
path: root/rpkid/rpki/gctx.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid/rpki/gctx.py')
-rw-r--r--rpkid/rpki/gctx.py161
1 files changed, 161 insertions, 0 deletions
diff --git a/rpkid/rpki/gctx.py b/rpkid/rpki/gctx.py
new file mode 100644
index 00000000..33bded85
--- /dev/null
+++ b/rpkid/rpki/gctx.py
@@ -0,0 +1,161 @@
+# $Id$
+
+# Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
+#
+# 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 ARIN DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ARIN 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.
+
+"""
+Global context for rpkid. Probably should be renamed rpkid.py, but
+the identifier gctx is scattered all through the code at the moment.
+"""
+
+import traceback, os, time, getopt, sys, MySQLdb, lxml.etree
+import rpki.resource_set, rpki.up_down, rpki.left_right, rpki.x509, rpki.sql
+import rpki.https, rpki.config, rpki.cms, rpki.exceptions, rpki.relaxng, rpki.log
+
+class global_context(object):
+ """A container for various global parameters."""
+
+ def __init__(self, cfg):
+
+ self.db = MySQLdb.connect(user = cfg.get("sql-username"),
+ db = cfg.get("sql-database"),
+ passwd = cfg.get("sql-password"))
+ self.cur = self.db.cursor()
+
+ self.cms_ta_irdb = rpki.x509.X509(Auto_file = cfg.get("cms-ta-irdb"))
+ self.cms_ta_irbe = rpki.x509.X509(Auto_file = cfg.get("cms-ta-irbe"))
+ self.cms_key = rpki.x509.RSA(Auto_file = cfg.get("cms-key"))
+ self.cms_certs = rpki.x509.X509_chain(Auto_files = cfg.multiget("cms-cert"))
+
+ self.https_key = rpki.x509.RSA(Auto_file = cfg.get("https-key"))
+ self.https_certs = rpki.x509.X509_chain(Auto_files = cfg.multiget("https-cert"))
+ self.https_ta_irdb = rpki.x509.X509_chain(Auto_files = cfg.multiget("https-ta-irdb"))
+ self.https_ta_irbe = rpki.x509.X509_chain(Auto_files = cfg.multiget("https-ta-irbe"))
+
+ self.irdb_url = cfg.get("irdb-url")
+
+ self.https_server_host = cfg.get("server-host", "")
+ self.https_server_port = int(cfg.get("server-port", "4433"))
+
+ self.publication_kludge_base = cfg.get("publication-kludge-base", "publication/")
+
+ self.sql_cache = {}
+ self.sql_dirty = set()
+
+ def irdb_query(self, self_id, child_id = None):
+ """Perform an IRDB callback query. In the long run this should not
+ be a blocking routine, it should instead issue a query and set up a
+ handler to receive the response. For the moment, though, we are
+ doing simple lock step and damn the torpedos. Not yet doing
+ anything useful with subject name. Most likely this function should
+ really be wrapped up in a class that carries both the query result
+ and also the intermediate state needed for the event-driven code
+ that this function will need to become.
+ """
+
+ rpki.log.trace()
+
+ q_msg = rpki.left_right.msg()
+ q_msg.append(rpki.left_right.list_resources_elt())
+ q_msg[0].type = "query"
+ q_msg[0].self_id = self_id
+ q_msg[0].child_id = child_id
+ q_elt = q_msg.toXML()
+ rpki.relaxng.left_right.assertValid(q_elt)
+ q_cms = rpki.cms.xml_sign(q_elt, self.cms_key, self.cms_certs)
+ r_cms = rpki.https.client(
+ privateKey = self.https_key,
+ certChain = self.https_certs,
+ x509TrustList = self.https_ta_irdb,
+ url = self.irdb_url,
+ msg = q_cms)
+ r_elt = rpki.cms.xml_verify(r_cms, self.cms_ta_irdb)
+ rpki.relaxng.left_right.assertValid(r_elt)
+ r_msg = rpki.left_right.sax_handler.saxify(r_elt)
+ if len(r_msg) == 0 or not isinstance(r_msg[0], rpki.left_right.list_resources_elt) or r_msg[0].type != "reply":
+ raise rpki.exceptions.BadIRDBReply, "Unexpected response to IRDB query: %s" % lxml.etree.tostring(r_msg.toXML(), pretty_print = True, encoding = "us-ascii")
+ return rpki.resource_set.resource_bag(
+ as = r_msg[0].as,
+ v4 = r_msg[0].ipv4,
+ v6 = r_msg[0].ipv6,
+ valid_until = r_msg[0].valid_until)
+
+ def sql_cache_clear(self):
+ """Clear the object cache."""
+ self.sql_cache.clear()
+
+ def sql_assert_pristine(self):
+ """Assert that there are no dirty objects in the cache."""
+ assert not self.sql_dirty, "Dirty objects in SQL cache: %s" % self.sql_dirty
+
+ def sql_sweep(self):
+ """Write any dirty objects out to SQL."""
+ for s in self.sql_dirty.copy():
+ rpki.log.debug("Sweeping %s" % repr(s))
+ if s.sql_deleted:
+ s.sql_delete()
+ else:
+ s.sql_store()
+ self.sql_assert_pristine()
+
+ def left_right_handler(self, query, path):
+ """Process one left-right PDU."""
+ rpki.log.trace()
+ try:
+ q_elt = rpki.cms.xml_verify(query, self.cms_ta_irbe)
+ rpki.relaxng.left_right.assertValid(q_elt)
+ q_msg = rpki.left_right.sax_handler.saxify(q_elt)
+ r_msg = q_msg.serve_top_level(self)
+ r_elt = r_msg.toXML()
+ rpki.relaxng.left_right.assertValid(r_elt)
+ reply = rpki.cms.xml_sign(r_elt, self.cms_key, self.cms_certs)
+ self.sql_sweep()
+ return 200, reply
+ except lxml.etree.DocumentInvalid:
+ rpki.log.warn("Received reply document does not pass schema check: " + lxml.etree.tostring(r_elt, pretty_print = True))
+ rpki.log.warn(traceback.format_exc())
+ return 500, "Schema violation"
+ except Exception, data:
+ rpki.log.error(traceback.format_exc())
+ return 500, "Unhandled exception %s" % data
+
+ def up_down_handler(self, query, path):
+ """Process one up-down PDU."""
+ rpki.log.trace()
+ try:
+ child_id = path.partition("/up-down/")[2]
+ if not child_id.isdigit():
+ raise rpki.exceptions.BadContactURL, "Bad path: %s" % path
+ child = rpki.left_right.child_elt.sql_fetch(self, long(child_id))
+ if child is None:
+ raise rpki.exceptions.ChildNotFound, "Could not find child %s" % child_id
+ reply = child.serve_up_down(query)
+ self.sql_sweep()
+ return 200, reply
+ except Exception, data:
+ rpki.log.error(traceback.format_exc())
+ return 400, "Could not process PDU: %s" % data
+
+ def cronjob_handler(self, query, path):
+ """Periodic tasks. As simple as possible for now, may need to break
+ this up into separate handlers later.
+ """
+
+ rpki.log.trace()
+ for s in rpki.left_right.self_elt.sql_fetch_all(self):
+ s.client_poll()
+ s.update_children()
+ s.regenerate_crls_and_manifests()
+ self.sql_sweep()
+ return 200, "OK"