diff --git a/ring.py b/ring.py new file mode 100755 index 0000000..31829b4 --- /dev/null +++ b/ring.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +import argparse +import itertools +import json +import pydot +import random +import time +import urllib.request +from dns import resolver + +parser = argparse.ArgumentParser(description=''' +Draw a graph from ring BGP data. A PNG file will be generated with name +'YYYY-MM-DD-HH-MM-route.png'. +During the generation, all the paths are printed to the console in case you want +to see prepending and such. +''') +parser.add_argument('--route', dest='route', type=str, + help='IPv4 or IPv6 range present in the DFZ') + +args = parser.parse_args() +print(args.route) + +def pairwise(iterable): + a, b = itertools.tee(iterable) + next(b, None) + return zip(a, b) + +paths = {} + +ring_json = urllib.request.urlopen(f'http://lg02.infra.ring.nlnog.net/bgplgd/rib?prefix={args.route}') + +ring_data = json.load(ring_json) +prefix = ring_data['rib'][0]['prefix'] +for peer in ring_data['rib']: + path = [] + for asn in peer['aspath'].split(): + path.append(asn) + path.append(prefix) + paths[peer['neighbor']['description']] = path + +#json_graph = json.JSONEncoder().encode(paths) +nodes = {} +edges = {} + +dot_graph = pydot.Dot('BGPMAP', graph_type='digraph') + +resolv = resolver.Resolver() +resolv.timeout = 0.5 + +for peer in paths: + print(peer, paths[peer]) + + string_prepended_path = ['AS'+v for v in paths[peer][:-1]] + print(string_prepended_path) + + for previous_asn, asn in pairwise(paths[peer]): + + try: + as_name = resolv.query(f"AS{previous_asn}.asn.cymru.com", "TXT") + as_name = as_name.response.answer[0].to_text().split('|')[4] + as_name = as_name.strip().replace("'","").replace('"','') + except Exception as e: + print(e, previous_asn) + as_name = '' + + print(as_name) + edge_tuple = (previous_asn, asn) + color = "#%x" % random.randint(0, 16777215) + + if edge_tuple not in edges: + edge = pydot.Edge(*edge_tuple) + edge.set_style("dashed") + edge.set_color(color) + dot_graph.add_edge(edge) + edges[edge_tuple] = edge + + if previous_asn not in nodes: + nodes[previous_asn] = pydot.Node(previous_asn) + label = 'AS' + previous_asn + '\n' + as_name + nodes[previous_asn].set_label(label) + dot_graph.add_node(nodes[previous_asn]) + +current_time = time.localtime() +filename = '{}-{}-{}-{}-{}-{}.png'.format( + "{:04d}".format(current_time.tm_year), + "{:02d}".format(current_time.tm_mon), + "{:02d}".format(current_time.tm_mday), + "{:02d}".format(current_time.tm_hour), + "{:02d}".format(current_time.tm_min), + args.route.replace('/', '-') + ) +dot_graph.write_png(filename)