RPKI Engine  1.0
rcynic.py (4054)
Go to the documentation of this file.
00001 """
00002 Prototype of an iterator class to parse the output of an rcynic run.
00003 This script will almost certainly move to the library package once
00004 it's stable.
00005 
00006 $Id: rcynic.py 4054 2011-10-18 22:56:05Z melkins $
00007 
00008 Copyright (C) 2010-2011  Internet Systems Consortium ("ISC")
00009 
00010 Permission to use, copy, modify, and distribute this software for any
00011 purpose with or without fee is hereby granted, provided that the above
00012 copyright notice and this permission notice appear in all copies.
00013 
00014 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00015 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00016 AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00017 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00018 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00019 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00020 PERFORMANCE OF THIS SOFTWARE.
00021 """
00022 
00023 import sys, os, rpki.x509, rpki.exceptions
00024 from xml.etree.ElementTree import ElementTree
00025 
00026 class UnknownObject(rpki.exceptions.RPKI_Exception):
00027   """
00028   Unrecognized object in rcynic result cache.
00029   """
00030 
00031 class NotRsyncURI(rpki.exceptions.RPKI_Exception):
00032   """
00033   URI is not an rsync URI.
00034   """
00035 
00036 class rcynic_object(object):
00037   """
00038   An object read from rcynic cache.
00039   """
00040 
00041   def __init__(self, filename, **kwargs):
00042     self.filename = filename
00043     for k, v in kwargs.iteritems():
00044       setattr(self, k, v)
00045     self.obj = self.obj_class(DER_file = filename)
00046 
00047   def __repr__(self):
00048     return "<%s %s %s at 0x%x>" % (self.__class__.__name__, self.uri, self.resources, id(self))
00049 
00050   def show_attrs(self, *attrs):
00051     """
00052     Print a bunch of object attributes, quietly ignoring any that
00053     might be missing.
00054     """
00055     for a in attrs:
00056       try:
00057         print "%s: %s" % (a.capitalize(), getattr(self, a))
00058       except AttributeError:
00059         pass
00060 
00061   def show(self):
00062     """
00063     Print common object attributes.
00064     """
00065     self.show_attrs("filename", "uri", "status", "timestamp")
00066 
00067 class rcynic_certificate(rcynic_object):
00068   """
00069   A certificate from rcynic cache.
00070   """
00071 
00072   obj_class = rpki.x509.X509
00073 
00074   def __init__(self, filename, **kwargs):
00075     rcynic_object.__init__(self, filename, **kwargs)
00076     self.notBefore = self.obj.getNotBefore()
00077     self.notAfter =  self.obj.getNotAfter()
00078     self.aia_uri = self.obj.get_aia_uri()
00079     self.sia_directory_uri = self.obj.get_sia_directory_uri()
00080     self.manifest_uri = self.obj.get_sia_manifest_uri()
00081     self.resources = self.obj.get_3779resources()
00082     self.is_ca = self.obj.is_CA()
00083     self.serial = self.obj.getSerial()
00084     self.issuer = self.obj.getIssuer()
00085     self.subject = self.obj.getSubject()
00086     self.ski = self.obj.hSKI()
00087     self.aki = self.obj.hAKI()
00088 
00089   def show(self):
00090     """
00091     Print certificate attributes.
00092     """
00093     rcynic_object.show(self)
00094     self.show_attrs("notBefore", "notAfter", "aia_uri", "sia_directory_uri", "resources")
00095 
00096 class rcynic_roa(rcynic_object):
00097   """
00098   A ROA from rcynic cache.
00099   """
00100 
00101   obj_class = rpki.x509.ROA
00102 
00103   _afi_map = dict((cls.resource_set_type.afi, cls)
00104                   for cls in (rpki.resource_set.roa_prefix_set_ipv4,
00105                               rpki.resource_set.roa_prefix_set_ipv6))
00106 
00107   def __init__(self, filename, **kwargs):
00108     rcynic_object.__init__(self, filename, **kwargs)
00109     self.obj.extract()
00110     self.asID = self.obj.get_content().asID.get()
00111     self.prefix_sets = []
00112     for fam in self.obj.get_content().ipAddrBlocks:
00113       prefix_set = self._afi_map[fam.addressFamily.get()]()
00114       addr_type = prefix_set.resource_set_type.range_type.datum_type
00115       self.prefix_sets.append(prefix_set)
00116       for addr in fam.addresses:
00117         prefix = addr.address.get()
00118         prefixlen = len(prefix)
00119         prefix = addr_type(rpki.resource_set._bs2long(prefix, addr_type.bits, 0))
00120         maxprefixlen = addr.maxLength.get()
00121         prefix_set.append(prefix_set.prefix_type(prefix, prefixlen, maxprefixlen))
00122     self.ee = rpki.x509.X509(POW = self.obj.get_POW().certs()[0])
00123     self.notBefore = self.ee.getNotBefore()
00124     self.notAfter = self.ee.getNotAfter()
00125     self.aia_uri = self.ee.get_aia_uri()
00126     self.resources = self.ee.get_3779resources()
00127     self.issuer = self.ee.getIssuer()
00128     self.serial = self.ee.getSerial()
00129     self.subject = self.ee.getSubject()
00130     self.aki = self.ee.hAKI()
00131     self.ski = self.ee.hSKI()
00132 
00133   def show(self):
00134     """
00135     Print ROA attributes.
00136     """
00137     rcynic_object.show(self)
00138     self.show_attrs("notBefore", "notAfter", "aia_uri", "resources", "asID")
00139     if self.prefix_sets:
00140       print "Prefixes:", ",".join(str(i) for i in self.prefix_sets)
00141 
00142 class rcynic_ghostbuster(rcynic_object):
00143   """
00144   Ghostbuster record from the rcynic cache.
00145   """
00146 
00147   obj_class = rpki.x509.Ghostbuster
00148 
00149   def __init__(self, *args, **kwargs):
00150     rcynic_object.__init__(self, *args, **kwargs)
00151     self.obj.extract()
00152     self.vcard = self.obj.get_content()
00153     self.ee = rpki.x509.X509(POW = self.obj.get_POW().certs()[0])
00154     self.notBefore = self.ee.getNotBefore()
00155     self.notAfter = self.ee.getNotAfter()
00156     self.aia_uri = self.ee.get_aia_uri()
00157     self.issuer = self.ee.getIssuer()
00158     self.serial = self.ee.getSerial()
00159     self.subject = self.ee.getSubject()
00160     self.aki = self.ee.hAKI()
00161     self.ski = self.ee.hSKI()
00162 
00163   def show(self):
00164     rcynic_object.show(self)
00165     self.show_attrs("notBefore", "notAfter", "vcard")
00166 
00167 file_name_classes = {
00168   ".cer" : rcynic_certificate,
00169   ".gbr" : rcynic_ghostbuster,
00170   ".roa" : rcynic_roa }
00171 
00172 class rcynic_file_iterator(object):
00173   """
00174   Iterate over files in an rcynic output tree, yielding a Python
00175   representation of each object found.
00176   """
00177 
00178   def __init__(self, rcynic_root,
00179                authenticated_subdir = "authenticated"):
00180     self.rcynic_dir = os.path.join(rcynic_root, authenticated_subdir)
00181 
00182   def __iter__(self):
00183     for root, dirs, files in os.walk(self.rcynic_dir):
00184       for filename in files:
00185         filename = os.path.join(root, filename)
00186         ext = os.path.splitext(filename)[1]
00187         if ext in file_name_classes:
00188           yield file_name_classes[ext](filename)
00189 
00190 class validation_status_element(object):
00191     def __init__(self, *args, **kwargs):
00192         for k,v in kwargs.iteritems():
00193             setattr(self, k, v)
00194         self._obj = None
00195 
00196     def get_obj(self):
00197         if not self._obj:
00198             self._obj = self.file_class(filename=self.filename, uri=self.uri)
00199         return self._obj
00200 
00201     obj = property(get_obj)
00202 
00203 class rcynic_xml_iterator(object):
00204   """
00205   Iterate over validation_status entries in the XML output from an
00206   rcynic run.  Yields a tuple for each entry:
00207 
00208     timestamp, generation, status, object
00209 
00210   where URI, status, and timestamp are the corresponding values from
00211   the XML element, OK is a boolean indicating whether validation was
00212   considered succesful, and object is a Python representation of the
00213   object in question.  If OK is True, object will be from rcynic's
00214   authenticated output tree; otherwise, object will be from rcynic's
00215   unauthenticated output tree.
00216 
00217   Note that it is possible for the same URI to appear in more than one
00218   validation_status element; in such cases, the succesful case (OK
00219   True) should be the last entry (as rcynic will stop trying once it
00220   gets a good copy), but there may be multiple failures, which might
00221   or might not have different status codes.
00222   """
00223 
00224   def __init__(self, rcynic_root, xml_file,
00225                authenticated_old_subdir = "authenticated.old",
00226                unauthenticated_subdir = "unauthenticated"):
00227     self.rcynic_root = rcynic_root
00228     self.xml_file = xml_file
00229     self.authenticated_old_subdir = os.path.join(rcynic_root, authenticated_old_subdir)
00230     self.unauthenticated_subdir = os.path.join(rcynic_root, unauthenticated_subdir)
00231 
00232   base_uri = "rsync://"
00233 
00234   def uri_to_filename(self, uri):
00235     if uri.startswith(self.base_uri):
00236       return uri[len(self.base_uri):]
00237     else:
00238       raise NotRsyncURI, "Not an rsync URI %r" % uri
00239 
00240   def __iter__(self):
00241     for validation_status in ElementTree(file=self.xml_file).getroot().getiterator("validation_status"):
00242       timestamp = validation_status.get("timestamp")
00243       status = validation_status.get("status")
00244       uri = validation_status.text.strip()
00245       generation = validation_status.get("generation")
00246 
00247       # determine the path to this object
00248       filename = os.path.join(self.authenticated_old_subdir if generation == 'backup' else self.unauthenticated_subdir,
00249               self.uri_to_filename(uri))
00250 
00251       ext = os.path.splitext(filename)[1]
00252       if ext in file_name_classes:
00253           yield validation_status_element(timestamp=timestamp, generation=generation, uri=uri,
00254                   status=status, filename=filename, file_class=file_name_classes[ext])
00255 
00256 def label_iterator(xml_file):
00257     """
00258     Returns an iterator which contains all defined labels from an rcynic XML
00259     output file.  Each item is a tuple of the form
00260     (label, kind, description).
00261     """
00262 
00263     for label in ElementTree(file=xml_file).find("labels"):
00264         yield label.tag, label.get("kind"), label.text.strip()
 All Classes Namespaces Files Functions Variables Properties