diff --git a/ripedb/asset_ilines.py b/ripedb/asset_ilines.py new file mode 100755 index 0000000..3b0542d --- /dev/null +++ b/ripedb/asset_ilines.py @@ -0,0 +1,178 @@ +#!/usr/bin/python + +"""The purpose of this script is to take the RIPE NCC's routing database +and transform a comma separated list of AS-SETs (-as-sets) into IRCnet's +I-Line structure. It will look at all ipv4 and ipv6 route objects in a +certain AS number, and it finds the AS numbers by expanding the AS-SET +members. It uses the class speficied on the commandline (-class) +Example usage: +$ asset_ilines.py -as-sets AS-IP-MAN-PEERING-CIXP,AS-IP-MAN-PEERING-TIX \ + -class 210 -output ilines.as-set.conf +""" + +import getopt +import sys +import types +import time +import os +import getpass +import socket +import re + +def usage(): + print """Usage: + -h (-help): Help, this message + -a (-as-sets): The (comma separeted list of) AS set(s) to resolve + -o (-output): The output file to write + -y (-class): The Y-line class to put the I line in (default: 200)""" + pass + +def asn_to_route(_asn, _whois_server = "whois.ripe.net", + _prerequest_sleep_time = 1): + list = [] + time.sleep(_prerequest_sleep_time) + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.connect((_whois_server, 43)) + except: + return list + ifile = s.makefile('w') + ifile.write('-i origin AS'+_asn+'\r\n') + ifile.flush() + print("Fetching route/route6 from %s on %s" % (_asn, _whois_server)) + while True: + line = ifile.readline() + if not line: + break + matches = re.search('^route6?:[\s]*([0-9a-fA-F.:/]+)', line) + if not matches: + continue + list.append(matches.group(1)) + ifile.close() + print("%d route/route6 object(s) found for AS%s" % (len(list), _asn)) + return list + +def asset_to_asn(_asset, _whois_server = "whois.ripe.net", + _prerequest_sleep_time = 1): + list = [] + time.sleep(_prerequest_sleep_time) + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.connect((_whois_server, 43)) + except: + return list + ifile = s.makefile('w') + ifile.write(_asset+'\r\n') + ifile.flush() + print("Fetching %s from %s" % (_asset, _whois_server)) + + while True: + line = ifile.readline() + if not line: + break + matches = re.search('^members:.*AS([0-9]+)', line) + if not matches: + continue + list.append(matches.group(1)) + ifile.close() + print("%d AS numbers found for %s" % (len(list), _asset)) + return list + + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "ha:o:y:", + ["help", "assets=", "output=", "class="]) + except getopt.GetoptError, err: + print str(err) # will print something like "option -foo not recognized" + usage() + sys.exit(2) + + _assets = ["AS-IP-MAN-PEERING-TIX", "AS-IP-MAN-PEERING-CIXP", + "AS-IP-MAN-PEERING-SWISSIX"] + _class = 200 + _output = None + + for o,a in opts: + if o == "-h" or o == "-help": + usage() + sys.exit(2) + elif o == "-a" or o == "-as-sets": + _assets = a.split(',') + elif o == "-o" or o == "-output": + _output = a + elif o == "-y" or o == "-class": + _class = int(a) + else: + assert False, "unhandled option(s)" + + # Check input args a bit + if _output == None: + usage() + assert False, "-o (-output) Must set output file" + if type(_class) != types.IntType: + usage() + assert False, "-y (-class) must be an integer" + if len(_assets) < 1: + usage() + assert False, "-a (-as-sets) must be a list of AS-SETs" + + try: + ofile = open(_output, "w") + except: + assert False, "Coult not open output file" + + _data = {'as-set': {}, 'asn': {}} + for _asset in _assets: + asn_list = asset_to_asn (_asset) + _data['as-set'][_asset] = asn_list + for _asn in asn_list: + if _asn in _data['asn']: + continue + _data['asn'][_asn] = [] + + all_route_list = [] + for _asn in _data['asn'].keys(): + route_list = asn_to_route (_asn) + for _route in route_list: + if _route in all_route_list: + continue + _data['asn'][_asn].append(_route) + all_route_list = list(set(all_route_list + route_list)) + + # print(_data) + print("Objects found: %d route/route6, %d ASn, %d as-set" % + (len(all_route_list), len(_data['asn']), len(_assets))) + + ofile.write("# File generated on %s by %s@%s\n" % + (time.asctime(time.localtime(time.time())), + getpass.getuser(), socket.gethostname())) + ofile.write("# Commandline: %s\n" % ' '.join(sys.argv)) + ofile.write("# assets=%s output=%s class=%s\n" % + (','.join(_assets), _output, _class)) + + ofile.write("# Objects found: %d route/route6, %d ASn, %d as-set\n\n" % + (len(all_route_list), len(_data['asn']), len(_assets))) + + for _asset in _data['as-set']: + ofile.write("# %s: %s\n" % + (_asset, ', '.join(_data['as-set'][_asset]))) + ofile.write("#\n\n") + + output_linecount = 0 + for _asn in _data['asn']: + ofile.write("# AS%s (%d lines)\n" % + (_asn, len(_data['asn'][_asn]))) + for _route in _data['asn'][_asn]: + ofile.write("I%%*@%s%%%%%%%%%d%%%%\n" % + (_route, _class)) + output_linecount = output_linecount + 1 + ofile.write("\n") + ofile.write("# Output %d I-lines\n" % (output_linecount)) + + ofile.close() + +if __name__ == "__main__": + main()