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