#!/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). You can also use the flag -asns to specify a list of AS numbers. These two flags can be combined or used in isolation (as is shown by the examples below. Example usage: $ asset_ilines.py -as-sets AS-IP-MAN-PEERING-CIXP,AS-IP-MAN-PEERING-TIX \ -class 210 -output ilines.as-set.conf $ asset_ilines.py -asns 8404,20932 -class 220 -output ilines.asn.conf """ import getopt import sys import types import time import os import getpass import socket import re import textwrap def usage(): print """Usage: -h (-help): Help, this message -a (-as-sets): A (comma separeted list of) AS set(s) to lookup -l (-asns): A (comma separated list of) AS numbers to lookup -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%s\r\n' % (_asn))) ifile.flush() print("Fetching route/route6 for AS%s from %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:l:o:y:", ["help", "assets=", "asns=", "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 _asns = [20932] for o,a in opts: if o == "-h" or o == "-help": usage() sys.exit(2) elif o == "-a" or o == "-as-sets": if a == '': _assets = [] else: _assets = a.split(',') elif o == "-l" or o == "-asns": if a == '': _asns = [] else: _asns = 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 and len(_asns) < 1: usage() assert False,("-a (-as-sets) or -l (-asns) must be a comma " "separated list") 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] = [] _data['as-set']['LOCAL'] = _asns for _asn in _data['as-set']['LOCAL']: 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:\n# %s\n" % ("\n# ".join(textwrap.wrap(' '.join(sys.argv))))) 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:\n# %s\n" % (_asset, "\n# ".join(textwrap.fill( ', '.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()