aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2010-05-06 22:36:41 +0000
committerRob Austein <sra@hactrn.net>2010-05-06 22:36:41 +0000
commitb566995e5747f6f773f881819e9249736a13a321 (patch)
treed80f06b7838037294f33f37cf96544095ee6c344
parent66c3417a56d81494deeffad935585be045ad484e (diff)
Generate route and route6 objects from validated ROAs.
svn path=/scripts/roa-to-irr.py; revision=3240
-rw-r--r--scripts/roa-to-irr.py160
1 files changed, 160 insertions, 0 deletions
diff --git a/scripts/roa-to-irr.py b/scripts/roa-to-irr.py
new file mode 100644
index 00000000..788e8dd9
--- /dev/null
+++ b/scripts/roa-to-irr.py
@@ -0,0 +1,160 @@
+"""
+Generate IRR route and route6 objects from ROAs.
+
+$Id$
+
+Copyright (C) 2010 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.
+
+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
+PERFORMANCE OF THIS SOFTWARE.
+"""
+
+import os, socket, sys, getopt, errno, rpki.x509, rpki.ipaddrs
+
+class route_virtual(object):
+ """
+ All the interesting parts of a route object, as a virtual class.
+ """
+
+ def __init__(self, gski, 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]))
+ self.gski = gski
+ 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]
+
+ def __cmp__(self, other):
+ result = cmp(self.asn, other.asn)
+ if result == 0:
+ result = cmp(self.prefix, other.prefix)
+ if result == 0:
+ result = cmp(self.prefixlen, other.prefixlen)
+ if result == 0:
+ result = cmp(self.max_prefixlen, other.max_prefixlen)
+ if result == 0:
+ result = cmp(self.date, other.date)
+ return result
+
+ def __str__(self):
+ return "".join((
+ ("%-14s%s/%s\n" % (self.label, self.prefix, self.prefixlen)),
+ ("descr: %s\n" % self.uri),
+ ("origin: AS%d\n" % self.asn),
+ ("notify: %s\n" % irr_notify),
+ ("mnt-by: %s\n" % irr_mnt_by),
+ ("changed: %s %s\n" % (irr_changed_by, self.date)),
+ ("source: %s\n" % irr_source),
+ ("comment: %s/%s-%s\n" % (self.prefix, self.prefixlen, self.max_prefixlen))))
+
+class route_ipv4(route_virtual):
+ """
+ IPv4 route object.
+ """
+
+ addr_type = rpki.ipaddrs.v4addr
+ label = "route:"
+
+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):
+ """
+ A list of route objects.
+ """
+
+ def __init__(self, rcynic_dir):
+ for root, dirs, files in os.walk(rcynic_dir):
+ for f in files:
+ if f.endswith(".roa"):
+ gski = f[:-4]
+ 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](gski, uri, asnum, notBefore.strftime("%Y%m%d"), addr))
+ 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"
+output = None
+
+options = ["changed_by=", "help", "mnt_by=", "notify=", "output=", "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] if "=" in opt else opt) + "\n")
+ f.write(__doc__)
+ sys.exit(code)
+
+opts, argv = getopt.getopt(sys.argv[1:], "c:hm:n:o:s:?", options)
+for o, a in opts:
+ if o in ("-h", "--help", "-?"):
+ print __doc__
+ sys.exit(0)
+ elif o in ("-c", "--changed_by"):
+ irr_changed_by = 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 ("-s", "--source"):
+ source = a
+ else:
+ usage()
+
+if len(argv) != 1 or not os.path.isdir(argv[0]):
+ usage()
+
+routes = route_list("/u/sra/rpki/subvert-rpki.hactrn.net/rcynic/rcynic-data/authenticated")
+
+if output:
+ try:
+ os.makedirs(output)
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+ for r in routes:
+ open(os.path.join(output, r.gski), "w").write(str(r))
+else:
+ for r in routes:
+ print r