From 2f179b62925f83f075d9996f5cd263062b6e5bb2 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Sat, 11 Jan 2014 05:32:56 +0000 Subject: getopt -> argparse. Rewrite code that was still trying to use old rpki.POW.pkix API, removed some time back. svn path=/trunk/; revision=5631 --- scripts/roa-to-irr.py | 229 ++++++++++++++++++++------------------------------ 1 file changed, 91 insertions(+), 138 deletions(-) (limited to 'scripts/roa-to-irr.py') diff --git a/scripts/roa-to-irr.py b/scripts/roa-to-irr.py index 05ef05aa..01b2aac8 100644 --- a/scripts/roa-to-irr.py +++ b/scripts/roa-to-irr.py @@ -1,68 +1,48 @@ # $Id$ # -# Copyright (C) 2010-2012 Internet Systems Consortium ("ISC") +# Copyright (C) 2014 Dragon Research Labs ("DRL") +# Portions copyright (C) 2010--2012 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. """ Generate IRR route and route6 objects from ROAs. - -The only required argument is the name of a directory tree containing -the validated outpt of an rcynic run. If you follow the default -naming scheme this will be /some/where/rcynic-data/authenticated. - -If given the --output option, the argument to that option will be -interpreted as the name of a directory (which will be created if it -does not already exist) in which to write route and route6 objects, -one object per file. - -If not given the --output option, this program will write all the -route and route6 objects to standard output, separated by blank lines. -In this mode, if also given the --email option, the program will -generate a fake RFC (2)822 header suitable for piping all of this into -irr_rpsl_submit. - -The other options allow control of several required fields, to let you -change email addresses and so forth if the defaults values aren't -right. """ import os import socket import sys -import getopt +import argparse import errno import time import rpki.x509 -import rpki.ipaddrs -class route_virtual(object): +args = None + +class route(object): """ - All the interesting parts of a route object, as a virtual class. + Interesting parts of a route object. """ - def __init__(self, uri, asnum, date, asn1): - assert len(asn1[0]) <= self.addr_type.bits - x = 0L - for y in asn1[0]: - x = (x << 1) | y - x <<= (self.addr_type.bits - len(asn1[0])) + def __init__(self, label, uri, asnum, date, prefix, prefixlen, max_prefixlen): + self.label = label self.uri = uri self.asn = asnum self.date = date - self.prefix = self.addr_type(x) - self.prefixlen = len(asn1[0]) - self.max_prefixlen = self.prefixlen if asn1[1] is None else asn1[1] + self.prefix = prefix + self.prefixlen = prefixlen + self.max_prefixlen = self.prefixlen if max_prefixlen is None else max_prefixlen def __cmp__(self, other): result = cmp(self.asn, other.asn) @@ -81,35 +61,19 @@ class route_virtual(object): "%-14s%s/%s" % (self.label, self.prefix, self.prefixlen), "descr: %s/%s-%s" % (self.prefix, self.prefixlen, self.max_prefixlen), "origin: AS%d" % self.asn, - "notify: %s" % irr_notify, - "mnt-by: %s" % irr_mnt_by, - "changed: %s %s" % (irr_changed_by, self.date), - "source: %s" % irr_source, - "override: %s" % password if password is not None else None, + "notify: %s" % args.notify, + "mnt-by: %s" % args.mnt_by, + "changed: %s %s" % (args.changed_by, self.date), + "source: %s" % args.source, + "override: %s" % args.password if args.password is not None else None, "") return "\n".join(line for line in lines if line is not None) def write(self, output_directory): name = "%s-%s-%s-AS%d-%s" % (self.prefix, self.prefixlen, self.max_prefixlen, self.asn, self.date) - open(os.path.join(output_directory, name), "w").write(str(self)) - -class route_ipv4(route_virtual): - """ - IPv4 route object. - """ - - addr_type = rpki.ipaddrs.v4addr - label = "route:" + with open(os.path.join(output_directory, name), "w") as f: + f.write(str(self)) -class route_ipv6(route_virtual): - """ - IPv6 route object. - """ - - addr_type = rpki.ipaddrs.v6addr - label = "route6:" - -afi_map = { "\x00\x01" : route_ipv4, "\x00\x02" : route_ipv6 } class route_list(list): """ @@ -123,84 +87,73 @@ class route_list(list): path = os.path.join(root, f) uri = "rsync://" + path[len(rcynic_dir):].lstrip("/") roa = rpki.x509.ROA(DER_file = path) - version, asnum, asn1 = roa.extract().get() - assert version == 0, "ROA version is %d, expected 0" % version - notBefore = rpki.x509.X509(POW = roa.get_POW().certs()[0]).getNotBefore() - for afi, addrs in asn1: - for addr in addrs: - self.append(afi_map[afi](uri, asnum, notBefore.strftime("%Y%m%d"), addr)) + roa.extract() + assert roa.get_POW().getVersion() == 0, "ROA version is %d, expected 0" % roa.get_POW().getVersion() + asnum = roa.get_POW().getASID() + notBefore = roa.get_POW().certs()[0].getNotBefore().strftime("%Y%m%d") + v4, v6 = roa.get_POW().getPrefixes() + if v4 is not None: + for prefix, prefixlen, max_prefixlen in v4: + self.append(route("route:", uri, asnum, notBefore, prefix, prefixlen, max_prefixlen)) + if v6 is not None: + for prefix, prefixlen, max_prefixlen in v6: + self.append(route("route6:", uri, asnum, notBefore, prefix, prefixlen, max_prefixlen)) self.sort() for i in xrange(len(self) - 2, -1, -1): if self[i] == self[i + 1]: del self[i + 1] -# Main program - -whoami = "%s@%s" % (os.getlogin(), socket.gethostname()) - -irr_notify = whoami -irr_changed_by = whoami -irr_mnt_by = "MAINT-RPKI" -irr_source = "RPKI" -irr_from = whoami -output = None -email = False -password = None - -options = ["changed_by=", "email", "from=", "help", "mnt_by=", - "notify=", "output=", "password=", "source="] - -def usage(code = 1): - f = sys.stderr if code else sys.stdout - f.write("Usage: %s [options] rcynic-data/authenticated\n\nOptions:\n" % sys.argv[0]) - for opt in options: - f.write(" --" + ((opt[:-1] + " argument") if "=" in opt else opt) + "\n") - f.write(__doc__) - sys.exit(code) - -opts, argv = getopt.getopt(sys.argv[1:], "c:ef:hm:n:o:p:s:?", options) -for o, a in opts: - if o in ("-h", "--help", "-?"): - usage(0) - elif o in ("-c", "--changed_by"): - irr_changed_by = a - elif o in ("-e", "--email"): - email = True - elif o in ("-f", "--from"): - irr_from = a - elif o in ("-m", "--mnt_by"): - irr_mnt_by = a - elif o in ("-n", "--notify"): - irr_notify = a - elif o in ("-o", "--output"): - output = a - elif o in ("-p", "--password"): - password = a - elif o in ("-s", "--source"): - source = a +def email_header(f): + if args.email: + f.write("\n".join(( + "From %s" % args.email_from, + "Date: %s" % time.strftime("%d %b %Y %T %z"), + "From: %s" % args.email_from, + "Subject: Fake email header to make irr_rpsl_submit happy", + "Message-Id: <%s.%s@%s>" % (os.getpid(), time.time(), socket.gethostname()), + "", ""))) + +def main(): + + global args + whoami = "%s@%s" % (os.getlogin(), socket.gethostname()) + + parser = argparse.ArgumentParser(description = __doc__) + parser.add_argument("-c", "--changed_by", default = whoami, + help = "override \"changed:\" value") + parser.add_argument("-f", "--from", dest = "email_from", default = whoami, + help = "override \"from:\" header when using --email") + parser.add_argument("-m", "--mnt_by", default = "MAINT-RPKI", + help = "override \"mnt-by:\" value") + parser.add_argument("-n", "--notify", default = whoami, + help = "override \"notify:\" value") + parser.add_argument("-p", "--password", + help = "specify \"override:\" password") + parser.add_argument("-s", "--source", default = "RPKI", + help = "override \"source:\" value") + group = parser.add_mutually_exclusive_group() + group.add_argument("-e", "--email", action = "store_true", + help = "generate fake RFC 822 header suitable for piping to irr_rpsl_submit") + group.add_argument("-o", "--output", + help = "write route and route6 objects to directory OUTPUT, one object per file") + parser.add_argument("authenticated_directory", + help = "directory tree containing authenticated rcynic output") + args = parser.parse_args() + + if not os.path.isdir(args.authenticated_directory): + sys.exit("\"%s\" is not a directory" % args.authenticated_directory) + + routes = route_list(args.authenticated_directory) + + if args.output: + if not os.path.isdir(args.output): + os.makedirs(args.output) + for r in routes: + r.write(args.output) else: - usage() - -if len(argv) != 1 or not os.path.isdir(argv[0]): - usage() - -routes = route_list(argv[0]) - -if output: - try: - os.makedirs(output) - except OSError, e: - if e.errno != errno.EEXIST: - raise - for r in routes: - r.write(output) -else: - if email: - print "From", irr_from - print "Date:", time.strftime("%d %b %Y %T %z") - print "From:", irr_from - print "Subject: Fake email header to make irr_rpsl_submit happy" - print "Message-Id: <%s.%s@%s>" % (os.getpid(), time.time(), socket.gethostname()) - print - for r in routes: - print r + email_header(sys.stdout) + for r in routes: + sys.stdout.write("%s\n" % r) + +if __name__ == "__main__": + main() -- cgit v1.2.3