aboutsummaryrefslogtreecommitdiff
path: root/rpkid/rpki/rpkid_tasks.py
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid/rpki/rpkid_tasks.py')
-rw-r--r--rpkid/rpki/rpkid_tasks.py152
1 files changed, 141 insertions, 11 deletions
diff --git a/rpkid/rpki/rpkid_tasks.py b/rpkid/rpki/rpkid_tasks.py
index a1657d97..04e1c0df 100644
--- a/rpkid/rpki/rpkid_tasks.py
+++ b/rpkid/rpki/rpkid_tasks.py
@@ -1,17 +1,19 @@
# $Id$
#
-# Copyright (C) 2012-2013 Internet Systems Consortium ("ISC")
+# Copyright (C) 2014 Dragon Research Labs ("DRL")
+# Portions copyright (C) 2012--2013 Internet Systems Consortium ("ISC")
#
# 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.
+# copyright notices and this permission notice appear in all copies.
#
-# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS. IN NO EVENT SHALL ISC 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
+# THE SOFTWARE IS PROVIDED "AS IS" AND DRL AND ISC DISCLAIM ALL
+# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL OR
+# ISC 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.
"""
@@ -27,6 +29,18 @@ import rpki.sundial
import rpki.publication
import rpki.exceptions
+task_classes = ()
+
+def queue_task(cls):
+ """
+ Class decorator to add a new task class to task_classes.
+ """
+
+ global task_classes
+ task_classes += (cls,)
+ return cls
+
+
class CompletionHandler(object):
"""
Track one or more scheduled rpkid tasks and execute a callback when
@@ -136,6 +150,7 @@ class AbstractTask(object):
pass
+@queue_task
class PollParentTask(AbstractTask):
"""
Run the regular client poll cycle with each of this self's
@@ -203,6 +218,7 @@ class PollParentTask(AbstractTask):
self.parent_iterator()
+@queue_task
class UpdateChildrenTask(AbstractTask):
"""
Check for updated IRDB data for all of this self's children and
@@ -258,6 +274,8 @@ class UpdateChildrenTask(AbstractTask):
if ca_detail.state == "active":
old_resources = child_cert.cert.get_3779resources()
new_resources = old_resources & irdb_resources & ca_detail.latest_ca_cert.get_3779resources()
+ old_aia = child_cert.cert.get_AIA()[0]
+ new_aia = ca_detail.ca_cert_uri
if new_resources.empty():
rpki.log.debug("Resources shrank to the null set, "
@@ -267,9 +285,11 @@ class UpdateChildrenTask(AbstractTask):
ca_detail.generate_crl(publisher = self.publisher)
ca_detail.generate_manifest(publisher = self.publisher)
- elif old_resources != new_resources or (old_resources.valid_until < self.rsn and
- irdb_resources.valid_until > self.now and
- old_resources.valid_until != irdb_resources.valid_until):
+ elif (old_resources != new_resources or
+ old_aia != new_aia or
+ (old_resources.valid_until < self.rsn and
+ irdb_resources.valid_until > self.now and
+ old_resources.valid_until != irdb_resources.valid_until)):
rpki.log.debug("Need to reissue child %s certificate SKI %s" % (
self.child.child_handle, child_cert.cert.gSKI()))
@@ -321,6 +341,7 @@ class UpdateChildrenTask(AbstractTask):
self.exit()
+@queue_task
class UpdateROAsTask(AbstractTask):
"""
Generate or update ROAs for this self.
@@ -450,6 +471,7 @@ class UpdateROAsTask(AbstractTask):
self.exit()
+@queue_task
class UpdateGhostbustersTask(AbstractTask):
"""
Generate or update Ghostbuster records for this self.
@@ -547,6 +569,112 @@ class UpdateGhostbustersTask(AbstractTask):
rpki.log.warn("Could not fetch Ghostbuster record requests for %s, skipping: %s" % (self.self_handle, e))
self.exit()
+
+@queue_task
+class UpdateEECertificatesTask(AbstractTask):
+ """
+ Generate or update EE certificates for this self.
+
+ Not yet sure what kind of scaling constraints this task might have,
+ so keeping it simple for initial version, we can optimize later.
+ """
+
+ def start(self):
+ rpki.log.trace()
+ self.gctx.checkpoint()
+ rpki.log.debug("Self %s[%d] updating EE certificates" % (self.self_handle, self.self_id))
+
+ self.gctx.irdb_query_ee_certificate_requests(self.self_handle,
+ self.got_requests,
+ self.get_requests_failed)
+
+ def got_requests(self, requests):
+
+ try:
+ self.gctx.checkpoint()
+ if self.gctx.sql.dirty:
+ rpki.log.warn("Unexpected dirty SQL cache, flushing")
+ self.gctx.sql.sweep()
+
+ publisher = rpki.rpkid.publication_queue()
+
+ existing = dict()
+ for ee in self.ee_certificates:
+ gski = ee.gski
+ if gski not in existing:
+ existing[gski] = set()
+ existing[gski].add(ee)
+
+ ca_details = set()
+
+ for req in requests:
+ ees = existing.pop(req.gski, ())
+ resources = rpki.resource_set.resource_bag(
+ asn = req.asn,
+ v4 = req.ipv4,
+ v6 = req.ipv6,
+ valid_until = req.valid_until)
+ covering = self.find_covering_ca_details(resources)
+ ca_details.update(covering)
+
+ for ee in ees:
+ if ee.ca_detail in covering:
+ rpki.log.debug("Updating existing EE certificate for %s %s" % (req.gski, resources))
+ ee.reissue(
+ resources = resources,
+ publisher = publisher)
+ covering.remove(ee.ca_detail)
+ else:
+ rpki.log.debug("Existing EE certificate for %s %s is no longer covered" % (req.gski, resources))
+ ee.revoke(publisher = publisher)
+
+ for ca_detail in covering:
+ rpki.log.debug("No existing EE certificate for %s %s" % (req.gski, resources))
+ rpki.rpkid.ee_cert_obj.create(
+ ca_detail = ca_detail,
+ subject_name = rpki.x509.X501DN.from_cn(req.cn, req.sn),
+ subject_key = req.pkcs10.getPublicKey(),
+ resources = resources,
+ publisher = publisher,
+ eku = req.eku or None)
+
+ # Anything left is an orphan
+ for ees in existing.values():
+ for ee in ees:
+ ca_details.add(ee.ca_detail)
+ ee.revoke(publisher = publisher)
+
+ self.gctx.sql.sweep()
+
+ for ca_detail in ca_details:
+ ca_detail.generate_crl(publisher = publisher)
+ ca_detail.generate_manifest(publisher = publisher)
+
+ self.gctx.sql.sweep()
+
+ self.gctx.checkpoint()
+ publisher.call_pubd(self.exit, self.publication_failed)
+
+ except (SystemExit, rpki.async.ExitNow):
+ raise
+ except Exception, e:
+ rpki.log.traceback()
+ rpki.log.warn("Could not update EE certificates for %s, skipping: %s" % (self.self_handle, e))
+ self.exit()
+
+ def publication_failed(self, e):
+ rpki.log.traceback()
+ rpki.log.warn("Couldn't publish EE certificate updates for %s, skipping: %s" % (self.self_handle, e))
+ self.gctx.checkpoint()
+ self.exit()
+
+ def get_requests_failed(self, e):
+ rpki.log.traceback()
+ rpki.log.warn("Could not fetch EE certificate requests for %s, skipping: %s" % (self.self_handle, e))
+ self.exit()
+
+
+@queue_task
class RegenerateCRLsAndManifestsTask(AbstractTask):
"""
Generate new CRLs and manifests as necessary for all of this self's
@@ -595,6 +723,8 @@ class RegenerateCRLsAndManifestsTask(AbstractTask):
self.gctx.checkpoint()
self.exit()
+
+@queue_task
class CheckFailedPublication(AbstractTask):
"""
Periodic check for objects we tried to publish but failed (eg, due