RPKI Engine 1.0

rcynic.py (3884)

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 3884 2011-06-17 18:50:12Z sra $
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 rcynic_xml_iterator(object):
00191   """
00192   Iterate over validation_status entries in the XML output from an
00193   rcynic run.  Yields a tuple for each entry:
00194 
00195     URI, OK, status, timestamp, object
00196 
00197   where URI, status, and timestamp are the corresponding values from
00198   the XML element, OK is a boolean indicating whether validation was
00199   considered succesful, and object is a Python representation of the
00200   object in question.  If OK is True, object will be from rcynic's
00201   authenticated output tree; otherwise, object will be from rcynic's
00202   unauthenticated output tree.
00203 
00204   Note that it is possible for the same URI to appear in more than one
00205   validation_status element; in such cases, the succesful case (OK
00206   True) should be the last entry (as rcynic will stop trying once it
00207   gets a good copy), but there may be multiple failures, which might
00208   or might not have different status codes.
00209   """
00210 
00211   def __init__(self, rcynic_root, xml_file,
00212                authenticated_subdir = "authenticated",
00213                authenticated_old_subdir = "authenticated.old",
00214                unauthenticated_subdir = "unauthenticated"):
00215     self.rcynic_root = rcynic_root
00216     self.xml_file = xml_file
00217     self.authenticated_subdir = os.path.join(rcynic_root, authenticated_subdir)
00218     self.authenticated_old_subdir = os.path.join(rcynic_root, authenticated_old_subdir)
00219     self.unauthenticated_subdir = os.path.join(rcynic_root, unauthenticated_subdir)
00220 
00221   base_uri = "rsync://"
00222 
00223   def uri_to_filename(self, uri):
00224     if uri.startswith(self.base_uri):
00225       return uri[len(self.base_uri):]
00226     else:
00227       raise NotRsyncURI, "Not an rsync URI %r" % uri
00228 
00229   def __iter__(self):
00230 
00231     for validation_status in ElementTree(file = self.xml_file).getroot().getiterator("validation_status"):
00232       timestamp = validation_status.get("timestamp")
00233       status = validation_status.get("status")
00234       uri = validation_status.text.strip()
00235       ok = status == "validation_ok"
00236       filename = os.path.join(self.authenticated_subdir if ok else self.unauthenticated_subdir, self.uri_to_filename(uri))
00237       ext = os.path.splitext(filename)[1]
00238       if ext in file_name_classes:
00239         yield file_name_classes[ext](filename = filename, uri = uri, ok = ok, status = status, timestamp = timestamp)
00240 
00241 def label_iterator(xml_file):
00242     """
00243     Returns an iterator which contains all defined labels from an rcynic XML
00244     output file.  Each item is a tuple of the form
00245     (label, kind, description).
00246     """
00247 
00248     for label in ElementTree(file=xml_file).find("labels"):
00249         yield label.tag, label.get("kind"), label.text.strip()
00250 
00251 
00252 if __name__ == "__main__":
00253   rcynic_dir = os.path.normpath(os.path.join(sys.path[0], "..", "rcynic"))
00254   if False:
00255     try:
00256       for i in rcynic_file_iterator(os.path.join(rcynic_dir, "rcynic-data")):
00257         print i
00258     except IOError:
00259       pass
00260   if True:
00261     try:
00262       for i in rcynic_xml_iterator(os.path.join(rcynic_dir, "rcynic-data"),
00263                                    os.path.join(rcynic_dir, "rcynic.xml")):
00264         #print i
00265         i.show()
00266         print
00267     except IOError:
00268       pass
 All Classes Namespaces Files Functions Variables