aboutsummaryrefslogtreecommitdiff
path: root/scripts/roa-to-irr.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/roa-to-irr.py')
-rw-r--r--scripts/roa-to-irr.py229
1 files changed, 91 insertions, 138 deletions
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()