-
Notifications
You must be signed in to change notification settings - Fork 9
/
bgp_path_parser.py
95 lines (83 loc) · 3.51 KB
/
bgp_path_parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import sys
import json
import sqlite3
class BgpPaths(object):
""" Class for storing and sanitizing forward and reverse BGP paths """
def __init__(self):
self.forward_paths = set()
self.reverse_paths = set()
self.ixp = set()
def extract_ixp(self, peeringdb_file):
# PeeringDB json dump
if peeringdb_file.endswith('json'):
with open(peeringdb_file) as f:
data = json.load(f)
for i in data['net']['data']:
if i['info_type'] == 'Route Server':
self.ixp.add(str(i['asn']))
# PeeringDB sqlite dump
elif peeringdb_file.endswith('sqlite'):
conn = sqlite3.connect(peeringdb_file)
c = conn.cursor()
for row in c.execute("SELECT asn, info_type FROM 'peeringdb_network'"):
asn, info_type = row
if info_type == 'Route Server':
self.ixp.add(str(asn))
else:
raise TypeError('PeeringDB file must be either a json file or a sqlite file.')
# Use IXP ASNs collected by https://github.com/vgiotsas/IxpRsCollector
# if no route servers were included in the peeringdb file
# if len(self.ixp) == 0:
# with open('RouteServerASNs_20171230.txt') as f:
# for line in f:
# if not line.startswith('#'):
# self.ixp.add(line.strip())
def parse_bgp_paths(self, rib_file):
""" Parse BGP paths from a RIB file.
Remove duplicated ASes, an artifact of BGP path prepending.
Sanitize the BGP paths: remove route server ASes;
remove paths containing reserved ASes;
remove paths with AS loops.
"""
with open(rib_file) as f:
for line in f:
asn_list = line.strip().split("|")
# remove IXPs
for asn in asn_list:
if asn in self.ixp:
asn_list.remove(asn)
# remove prepended ASes
asn_list = [v for i, v in enumerate(asn_list)
if i == 0 or v != asn_list[i-1]]
asn_set = set(asn_list)
# remove poisoned paths with AS loops
if len(asn_set) == 1 or not len(asn_list) == len(asn_set):
continue
else:
for asn in asn_list:
asn = int(asn)
# reserved ASN
if asn == 0 or asn == 23456 or asn >= 394240 \
or (61440 <= asn <= 131071) \
or (133120 <= asn <= 196607)\
or (199680 <= asn <= 262143)\
or (263168 <= asn <= 327679)\
or (328704 <= asn <= 393215):
break
else:
self.forward_paths.add("|".join(asn_list))
self.reverse_paths.add("|".join(asn_list[::-1]))
continue
def output_forward_paths(self):
f = open('sanitized_rib.txt', 'w')
for path in self.forward_paths:
f.write(path + '\n')
f.close()
if __name__ == '__main__':
if len(sys.argv) != 2:
print('Usage: python bgp_path_parser.py <peeringdb file>')
exit()
path = BgpPaths()
path.extract_ixp(sys.argv[1])
path.parse_bgp_paths('rib.txt')
path.output_forward_paths()