b51da2088e6d4d2338b6c41c3031f09b0348d02b
[dtbartle/mirror.git] / orionroutes.py
1 #!/usr/bin/python
2
3 # Configuration
4 ORION_TABLE =   1 # from /etc/iproute2/rt_tables
5 ORION_REALMS =  1 # from /etc/iproute2/rt_realms
6 ORION_VIAS =    [ "66.97.23.33", "66.97.28.65", "129.97.1.46" ]
7 ORION_GW =      "129.97.134.1"
8 ORION_SRC =     "129.97.134.42"
9 ORION_IFACE =   "eth0"
10
11 # Don't touch anything beyond here
12
13 import sys, iplib, SubnetTree
14 from ctypes import *
15
16 NETLINK_ROUTE =         0
17 AF_UNSPEC =             0
18 RT_SCOPE_UNIVERSE =     0
19 RTPROT_STATIC =         4
20 NLM_F_REPLACE =         0x100
21
22 def die(msg):
23     sys.stderr.write("orionroutes.py: %s\n" % msg)
24     sys.exit(1)
25
26 try:
27     libnl = cdll.LoadLibrary("libnl.so.1")
28     nl_geterror = CFUNCTYPE(c_char_p) (("nl_geterror", libnl), None)
29     nl_handle_alloc = CFUNCTYPE(c_void_p) (("nl_handle_alloc", libnl), None)
30     nl_connect = CFUNCTYPE(c_int, c_void_p, c_int) \
31         (("nl_connect", libnl), ((1, "handle", None), (1, "type", NETLINK_ROUTE)))
32     rtnl_route_alloc = CFUNCTYPE(c_void_p) (("rtnl_route_alloc", libnl), None)
33     rtnl_link_alloc_cache = CFUNCTYPE(c_void_p, c_void_p) \
34         (("rtnl_link_alloc_cache", libnl), ((1, "handle", None), ))
35     rtnl_link_name2i = CFUNCTYPE(c_int, c_void_p, c_char_p) \
36         (("rtnl_link_name2i", libnl), ((1, "cache", None), (1, "iface", -1)))
37     rtnl_route_set_oif = CFUNCTYPE(c_void_p, c_void_p, c_int) \
38         (("rtnl_route_set_oif", libnl), ((1, "route", None), (1, "iface", -1)))
39     nl_cache_free = CFUNCTYPE(None, c_void_p) \
40         (("nl_cache_free", libnl), ((1, "cache", None), ))
41     nl_addr_parse = CFUNCTYPE(c_void_p, c_char_p, c_int) \
42         (("nl_addr_parse", libnl), ((1, "dst", None), (1, "family", AF_UNSPEC)))
43     rtnl_route_set_dst = CFUNCTYPE(c_int, c_void_p, c_void_p) \
44         (("rtnl_route_set_dst", libnl), ((1, "route", None), (1, "dst", None)))
45     rtnl_route_set_pref_src = CFUNCTYPE(c_int, c_void_p, c_void_p) \
46         (("rtnl_route_set_pref_src", libnl), ((1, "route", None), (1, "src", None)))
47     nl_addr_put = CFUNCTYPE(None, c_void_p) \
48         (("nl_addr_put", libnl), ((1, "addr", None), ))
49     rtnl_route_set_gateway = CFUNCTYPE(c_int, c_void_p, c_void_p) \
50         (("rtnl_route_set_gateway", libnl), ((1, "route", None), (1, "gw", None)))
51     rtnl_route_set_table = CFUNCTYPE(None, c_void_p, c_int) \
52         (("rtnl_route_set_table", libnl), ((1, "route", None), (1, "table", -1)))
53     rtnl_route_set_scope = CFUNCTYPE(None, c_void_p, c_int) \
54         (("rtnl_route_set_scope", libnl), ((1, "route", None), (1, "scope", -1)))
55     rtnl_route_set_protocol = CFUNCTYPE(None, c_void_p, c_int) \
56         (("rtnl_route_set_protocol", libnl), ((1, "route", None), (1, "proto", -1)))
57     rtnl_route_set_realms = CFUNCTYPE(None, c_void_p, c_int) \
58         (("rtnl_route_set_realms", libnl), ((1, "route", None), (1, "realms", -1)))
59     rtnl_route_add = CFUNCTYPE(c_int, c_void_p, c_void_p, c_int) \
60         (("rtnl_route_add", libnl), ((1, "handle", None), (1, "route", None), (1, "flags", 0)))
61     rtnl_route_put = CFUNCTYPE(None, c_void_p) \
62         (("rtnl_route_put", libnl), ((1, "route", None), ))
63     nl_handle_destroy = CFUNCTYPE(None, c_void_p) \
64         (("nl_handle_destroy", libnl), ((1, "handle", None), ))
65     rtnl_route_alloc_cache = CFUNCTYPE(c_void_p, c_void_p) \
66         (("rtnl_route_alloc_cache", libnl), ((1, "handle", None), ))
67     nl_cache_get_first = CFUNCTYPE(c_void_p, c_void_p) \
68         (("nl_cache_get_first", libnl), ((1, "cache", None), ))
69     rtnl_route_get_table = CFUNCTYPE(c_int, c_void_p) \
70         (("rtnl_route_get_table", libnl), ((1, "route", None), ))
71     rtnl_route_get_dst = CFUNCTYPE(c_void_p, c_void_p) \
72         (("rtnl_route_get_dst", libnl), ((1, "route", None), ))
73     nl_addr2str = CFUNCTYPE(c_char_p, c_void_p, c_char_p, c_int) \
74         (("nl_addr2str", libnl), ((1, "addr", None), (1, "buffer", None), (1, "size", 0)))
75     rtnl_route_del = CFUNCTYPE(c_int, c_void_p, c_void_p, c_int) \
76         (("rtnl_route_del", libnl), ((1, "handle", None), (1, "route", None), (1, "flags", 0)))
77     nl_cache_get_next = CFUNCTYPE(c_void_p, c_void_p) \
78         (("nl_cache_get_next", libnl), ((1, "object", None), ))
79 except Exception,e:
80     die("Failed to load libnl: %s" % e)
81
82 def nl_die(func):
83     die("%s: %s" % (func, nl_geterror()))
84
85 ips = [[] for i in range(33)]
86 for line in sys.stdin:
87     try:
88         ip, mask, via, _, _, _, _, _, _, _ = line.strip().split(',')
89     except ValueError:
90         die("Malformed line: %s" % line.strip())
91
92     if via not in ORION_VIAS:
93         continue
94     bits = int(iplib.IPv4NetMask(mask).get_bits())
95     ips[bits].append(int(iplib.IPv4Address(ip)))
96
97 count = sum([len(ip_list) for ip_list in ips])
98 if count < 10:
99     die("Not enough routes (got %d)" % count)
100
101 cidrs = []
102 for bits in range(32, 1, -1):
103     ips[bits].sort()
104     last_ip = 0
105     for ip in ips[bits]:
106         if ip != last_ip and (ip ^ last_ip) == (1 << (32 - bits)):
107             ips[bits - 1].append(ip & (((1 << (bits - 1)) - 1) << (32 - (bits - 1))))
108             last_ip = 0
109         elif last_ip != 0:
110             cidrs.append((iplib.IPv4Address(last_ip), bits))
111         last_ip = ip
112     if last_ip != 0:
113         cidrs.append((iplib.IPv4Address(last_ip), bits))
114
115 nlh = nl_handle_alloc()
116 if nlh == None: nl_die("nl_handle_alloc")
117 if nl_connect(nlh, NETLINK_ROUTE) < 0: nl_die("nl_connect")
118
119 link_cache = rtnl_link_alloc_cache(nlh)
120 if link_cache == None: nl_die("rtnl_link_alloc")
121 iface = rtnl_link_name2i(link_cache, ORION_IFACE)
122 if iface < 0: nl_die("rtnl_link_name2i")
123 nl_cache_free(link_cache)
124
125 cidrs.sort(lambda (ip1, bits1), (ip2, bits2): cmp(ip1, ip2) if bits1 == bits2 else (bits1 - bits2))
126 tree = SubnetTree.SubnetTree()
127 for (ip, bits) in cidrs:
128     if str(ip) not in tree:
129         cidr = "%s/%s" % (ip, bits)
130         tree[cidr] = None
131
132         route = rtnl_route_alloc()
133         if route == None: nl_die("rtnl_route_alloc")
134
135         dstaddr = nl_addr_parse(cidr, AF_UNSPEC)
136         if dstaddr == None: nl_die("nl_addr_parse(%s)" % cidr)
137         if rtnl_route_set_dst(route, dstaddr) < 0: nl_die("rtnl_route_set_dst")
138         nl_addr_put(dstaddr)
139
140         srcaddr = nl_addr_parse(ORION_SRC, AF_UNSPEC)
141         if srcaddr == None: nl_die("nl_addr_parse(%s)" % ORION_SRC)
142         if rtnl_route_set_pref_src(route, srcaddr) < 0: nl_die("nl_route_set_pref_src")
143         nl_addr_put(srcaddr)
144
145         gwaddr = nl_addr_parse(ORION_GW, AF_UNSPEC)
146         if gwaddr == None: nl_die("nl_addr_parse(%s)" % ORION_GW)
147         if rtnl_route_set_gateway(route, gwaddr) < 0: nl_die("nl_route_set_gateway")
148         nl_addr_put(gwaddr)
149
150         rtnl_route_set_oif(route, iface)
151         rtnl_route_set_table(route, ORION_TABLE)
152         rtnl_route_set_scope(route, RT_SCOPE_UNIVERSE)
153         rtnl_route_set_protocol(route, RTPROT_STATIC)
154         rtnl_route_set_realms(route, ORION_REALMS)
155
156         if rtnl_route_add(nlh, route, NLM_F_REPLACE) < 0: nl_die("rtnl_route_add(dst=%s)" % cidr)
157         rtnl_route_put(route)
158
159 route_cache = rtnl_route_alloc_cache(nlh)
160 if route_cache == None: nl_die("rtnl_route_alloc_cache")
161 dstaddr_s = create_string_buffer(100)
162
163 route = nl_cache_get_first(route_cache)
164 while route != None:
165     table = rtnl_route_get_table(route)
166     if table != ORION_TABLE:
167         route = nl_cache_get_next(route)
168         continue
169
170     dstaddr = rtnl_route_get_dst(route)
171     if dstaddr == None:
172         continue
173     if nl_addr2str(dstaddr, dstaddr_s, sizeof(dstaddr_s)) == None: nl_die("nl_addr2str")
174     dstaddr = str(repr(dstaddr_s.value)).strip('\'').split('/')[0]
175
176     if dstaddr not in tree:
177         rtnl_route_del(nlh, route, 0)
178
179     route = nl_cache_get_next(route)
180
181 nl_cache_free(route_cache)
182
183 nl_handle_destroy(nlh)