-
Notifications
You must be signed in to change notification settings - Fork 21
/
mkroa
executable file
·133 lines (109 loc) · 5.12 KB
/
mkroa
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python3
from textwrap import dedent
from argparse import ArgumentParser
from formatter import Formatter
from filereader import get_communities_data
class BirdRoaFormatter(Formatter):
"""
Formatter for roa table in bird format
"""
def __init__(self, roa_table_name=False):
self.config = []
self.data = []
self.indent = ""
self.roa_table_name = roa_table_name
if not roa_table_name:
self.add_comment(dedent(
"""
This file is automatically generated.
You need to add the surrounding roa table statement yourself.
So Include it via:
roa table icvpn { include "roa.con?" }
"""
))
else:
self.indent = "\t"
self.config.append("roa table {tbl_name} {{".format(
tbl_name=roa_table_name
))
def add_data(self, asn, name, network, max_prefixlen):
self.data.append((network, max_prefixlen, asn, name))
def finalize(self):
maxlen_net = str(max(map(lambda x: len(x[0]), self.data)))
maxlen_asn = str(max(map(lambda x: len(str(x[2])), self.data)))
for entry in self.data:
self.config.append(
"{indent}roa {subnet:<{len_net}} max {max_prefix_len:>3} as {asn:>{len_asn}}; # {community}".format(
indent=self.indent, subnet=entry[0], max_prefix_len=entry[1], asn=entry[2],
community=entry[3], len_net=maxlen_net, len_asn=maxlen_asn
))
if self.roa_table_name:
self.config.append("}")
return "\n".join(self.config)
def add_roa(formatter, asn, community, network, prefixlen, default_max_prefixlen):
formatter.add_data(asn, community, network, max(prefixlen, default_max_prefixlen))
def create_config(srcdir, exclude, family, fmtclass, default_max_prefixlen, *args):
"""
Generates a configuration using all files in srcdir
(non-recursively) excluding communities from 'exclude'.
The files are read in lexicographic order to produce deterministic
results.
"""
formatter = fmtclass(*args)
if default_max_prefixlen is None:
if family == 'ipv6':
default_max_prefixlen = 64
elif family == 'ipv4':
default_max_prefixlen = 24
for community, data in get_communities_data(srcdir, exclude):
try:
networks = data['networks'][family]
asn = data['asn']
for network in sorted(networks):
prefixlen = int(network.split("/")[1])
add_roa(formatter, asn, community, network, prefixlen, default_max_prefixlen)
except (TypeError, KeyError):
pass
delegate = data.get('delegate', {})
for delegate_asn, delegate_networks in delegate.items():
for delegate_network in delegate_networks:
# not very beautiful, but everything more proper requires including a library
if family == 'ipv6' and '.' in delegate_network:
continue
if family == 'ipv4' and ':' in delegate_network:
continue
prefixlen = int(delegate_network.split("/")[1])
add_roa(formatter, delegate_asn, "{} (delegation)".format(community), delegate_network, prefixlen,
default_max_prefixlen)
print(formatter.finalize())
if __name__ == '__main__':
formatters = {
'bird': BirdRoaFormatter,
}
PARSER = ArgumentParser()
PARSER.add_argument('-f', '--format', dest='fmt',
help='Create config in format FMT. Possible values: {formatters}.'.format(
formatters=", ".join(formatters.keys())),
metavar='FMT',
choices=list(formatters.keys()),
default='bird')
PARSER.add_argument('-4', dest='family', action='store_const', const='ipv4',
help='Generate IPv4 config')
PARSER.add_argument('-6', dest='family', action='store_const', const='ipv6',
help='Generate IPv6 config')
PARSER.add_argument('-s', '--sourcedir', dest='src',
help="Use files in DIR as input files. Default: ../icvpn-meta/",
metavar="DIR", default="../icvpn-meta/")
PARSER.add_argument('-x', '--exclude', dest='exclude', action='append',
help='Exclude the comma-separated list of COMMUNITIES',
metavar='COMMUNITIES',
default=[])
PARSER.add_argument('-m', '--max', dest='default_max_prefixlen', default=None,
type=int, help='max prefix length to accept')
PARSER.add_argument('--bird-table-name', dest='bird_table_name',
help='Render ROA table with given name', default=False)
PARSER.set_defaults(family='ipv6')
ARGS = PARSER.parse_args()
create_config(ARGS.src, set(ARGS.exclude),
ARGS.family, formatters[ARGS.fmt],
ARGS.default_max_prefixlen, ARGS.bird_table_name)