diff --git a/2020-11-03-09-57-45.91.126.0-24.png b/2020-11-03-09-57-45.91.126.0-24.png new file mode 100644 index 0000000..26072be Binary files /dev/null and b/2020-11-03-09-57-45.91.126.0-24.png differ diff --git a/README.md b/README.md index 88e05d0..3e7b4cf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # ris-pydot-graph -Draw a graph from RIS 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. +Draw a graph from RIS 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. + +# Example image + +![sample-graph](2020-11-03-09-57-45.91.126.0-24.png) diff --git a/ris.py b/ris.py new file mode 100755 index 0000000..631fc1f --- /dev/null +++ b/ris.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +import argparse +import cymruwhois +import itertools +import json +import pydot +import random +import time +import urllib.request + +parser = argparse.ArgumentParser(description=''' +Draw a graph from RIS 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 = {} + +ris_json = urllib.request.urlopen('https://stat.ripe.net/data/looking-glass/data.json?resource={}'.format(args.route)) + +ris_data = json.load(ris_json) +prefix = ris_data['data']['rrcs'][0]['peers'][0]['prefix'] +for rrc in ris_data['data']['rrcs']: + for peer in rrc['peers']: + path = [] + for asn in peer['as_path'].split(): + path.append(asn) + path.append(prefix) + paths[peer['peer']] = path + +#json_graph = json.JSONEncoder().encode(paths) +nodes = {} +edges = {} + +dot_graph = pydot.Dot('BGPMAP', graph_type='digraph') + +cymruwhois_client = cymruwhois.Client() + +for peer in paths: + print(peer, paths[peer]) + + string_prepended_path = ['AS'+v for v in paths[peer][:-1]] + print(string_prepended_path) + cymruwhois_query = cymruwhois_client.lookupmany_dict(string_prepended_path) + + for previous_asn, asn in pairwise(paths[peer]): + + as_name = cymruwhois_query['AS'+previous_asn].owner + + 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)