aboutsummaryrefslogtreecommitdiff
path: root/rp/utils
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2014-04-14 23:44:51 +0000
committerRob Austein <sra@hactrn.net>2014-04-14 23:44:51 +0000
commitd0da4932f4b978b7e2dad580270a1023d9db35c5 (patch)
tree3353d76ad1f2eb3fe6f296908f9bc2ca2e314f63 /rp/utils
parentedda51cb862fcd8cf48a10489b180375db25984f (diff)
First cut at Python replacement for find_roa.
svn path=/trunk/; revision=5798
Diffstat (limited to 'rp/utils')
-rw-r--r--rp/utils/find-roa.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/rp/utils/find-roa.py b/rp/utils/find-roa.py
new file mode 100644
index 00000000..2f638c43
--- /dev/null
+++ b/rp/utils/find-roa.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+#
+# $Id$
+#
+# Copyright (C) 2014 Dragon Research Labs ("DRL")
+#
+# Permission to use, copy, modify, and/or 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 DRL DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL DRL 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.
+
+"""
+Replacement for old C-based find_roa program. Write real doc later.
+"""
+
+import os
+import sys
+import base64
+import argparse
+import rpki.POW
+import rpki.oids
+
+
+def check_dir(s):
+ if os.path.isdir(s):
+ return os.path.abspath(s)
+ else:
+ raise argparse.ArgumentTypeError("%r is not a directory" % s)
+
+
+def filename_to_uri(filename):
+ if not filename.startswith(args.rcynic_dir):
+ raise ValueError
+ return "rsync://" + filename[len(args.rcynic_dir):].lstrip("/")
+
+def uri_to_filename(uri):
+ if not uri.startswith("rsync://"):
+ raise ValueError
+ return os.path.join(args.rcynic_dir, uri[len("rsync://"):])
+
+
+class Prefix(object):
+ """
+ One prefix parsed from the command line.
+ """
+
+ def __init__(self, val):
+ addr, length = val.split("/")
+ length, sep, maxlength = length.partition("-")
+ self.prefix = rpki.POW.IPAddress(addr)
+ self.length = int(length)
+ self.maxlength = int(maxlength) if maxlength else self.length
+ if self.maxlength < self.length or self.length < 0 or self.length > self.prefix.bits:
+ raise ValueError
+ if self.prefix & ((1 << (self.prefix.bits - self.length)) - 1) != 0:
+ raise ValueError
+
+ def matches(self, roa):
+ return any(self.prefix == prefix and
+ self.length == length and
+ (not args.match_maxlength or
+ self.maxlength == maxlength or
+ (maxlength is None and
+ self.length == self.maxlength))
+ for prefix, length, maxlength in roa.prefixes)
+
+
+class ROA(rpki.POW.ROA):
+ """
+ Aspects of a ROA that we care about.
+ """
+
+ @classmethod
+ def parse(cls, fn):
+ assert fn.startswith(args.rcynic_dir)
+ self = cls.derReadFile(fn)
+ self.fn = fn
+ self.extractWithoutVerifying()
+ v4, v6 = self.getPrefixes()
+ self.prefixes = (v4 or ()) + (v6 or ())
+ return self
+
+ @property
+ def uri(self):
+ return filename_to_uri(self.fn)
+
+ @property
+ def formatted_prefixes(self):
+ for prefix in self.prefixes:
+ if prefix[2] is None or prefix[1] == prefix[2]:
+ yield "%s/%d" % (prefix[0], prefix[1])
+ else:
+ yield "%s/%d-%d" % (prefix[0], prefix[1], prefix[2])
+
+ def __str__(self):
+ prefixes = " ".join(self.formatted_prefixes)
+ return "ASN %s prefix(es) %s" % (self.getASID(), prefixes)
+
+ def show(self):
+ print "%s %s" % (self, self.uri if args.show_uris else self.fn)
+
+ def show_expiration(self):
+ print self
+ x = self.certs()[0]
+ uri = self.uri
+ while uri is not None:
+ print x.getNotAfter(), uri
+ for uri in x.getAIA() or ():
+ if uri.startswith("rsync://"):
+ break
+ else:
+ break
+ fn = uri_to_filename(uri)
+ if not os.path.exists(fn):
+ print "***** MISSING ******", uri
+ break
+ x = rpki.POW.X509.derReadFile(fn)
+ print
+
+
+parser = argparse.ArgumentParser(description = __doc__)
+parser.add_argument("--match-maxlength", action = "store_true", help = "pay attention to maxLength values")
+parser.add_argument("--show-expirations", action = "store_true", help = "show ROA chain expiration dates")
+parser.add_argument("--show-uris", action = "store_true", help = "show URIs instead of filenames")
+parser.add_argument("rcynic_dir", type = check_dir, help = "rcynic authenticated output directory")
+parser.add_argument("prefixes", type = Prefix, nargs = "+", help = "ROA prefix(es) to match")
+args = parser.parse_args()
+
+
+for root, dirs, files in os.walk(args.rcynic_dir):
+ for fn in files:
+ if fn.endswith(".roa"):
+ roa = ROA.parse(os.path.join(root, fn))
+ if any(prefix.matches(roa) for prefix in args.prefixes):
+ if args.show_expirations:
+ roa.show_expiration()
+ else:
+ roa.show()