diff options
Diffstat (limited to 'rpkid/rpki/rpkid_tasks.py')
-rw-r--r-- | rpkid/rpki/rpkid_tasks.py | 152 |
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 |