diff -r 1c5d2a037d54 gpl/lib/libnl/lib/route/route_obj.c
--- a/gpl/lib/libnl/lib/route/route_obj.c Wed Aug 15 17:43:52 2012 -0600
+++ b/gpl/lib/libnl/lib/route/route_obj.c Thu Aug 16 18:36:32 2012 -0600
@@ -983,6 +983,7 @@
}
if (old_nh) {
+ rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff);
if (route->rt_nr_nh == 0) {
/* If no nexthops have been provided via RTA_MULTIPATH
* we add it as regular nexthop to maintain backwards
@@ -1042,10 +1043,15 @@
if (route->rt_src)
rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
-
if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE)
rtmsg.rtm_scope = rtnl_route_guess_scope(route);
+ if (rtnl_route_get_nnexthops(route) == 1) {
+ struct rtnl_nexthop *nh;
+ nh = rtnl_route_nexthop_n(route, 0);
+ rtmsg.rtm_flags |= nh->rtnh_flags;
+ }
+
if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
goto nla_put_failure;
diff -r 1c5d2a037d54 lib/python-cp/_route.c
--- a/lib/python-cp/_route.c Wed Aug 15 17:43:52 2012 -0600
+++ b/lib/python-cp/_route.c Thu Aug 16 18:36:32 2012 -0600
@@ -150,6 +150,8 @@
static void nl_entry_cb(struct nl_object *new, struct nl_cache_cb_arg *arg);
static int nl_addr_Setter(struct nl_object *obj, PyObject *val, int hint, nl_addr_setter setter_fn);
static PyObject *nla_Getter(struct nl_addr *nla);
+static int sync_route(Route *route);
+static struct nl_cache *fill_route_cache(void);
static PyMethodDef _route_methods[] = {
{ "get_rules", get_rules, METH_VARARGS, "Get all routing rules." },
@@ -426,9 +428,30 @@
return res;
}
+static struct nl_cache *fill_route_cache(void)
+{
+ struct nl_sock *nls;
+ struct nl_cache *route_cache;
+
+ if ((nls = py_nls_connect()) == NULL) {
+ return NULL;
+ }
+
+ if (rtnl_route_alloc_cache(nls, 0, 0, &route_cache) < 0) {
+ nl_close(nls);
+ nl_socket_free(nls);
+ PyErr_Format(PyExc_IOError, "Failed to fill route cache.");
+ return NULL;
+ }
+
+ nl_close(nls);
+ nl_socket_free(nls);
+
+ return route_cache;
+}
+
static PyObject *get_routes(PyObject *mod, PyObject *args)
{
- struct nl_sock *nls;
struct nl_cache *route_cache;
PyObject *res;
struct nl_cache_cb_arg cbarg;
@@ -439,14 +462,7 @@
return NULL;
}
- if ((nls = py_nls_connect()) == NULL) {
- return NULL;
- }
-
- if (rtnl_route_alloc_cache(nls, 0, 0, &route_cache) < 0) {
- nl_close(nls);
- nl_socket_free(nls);
- PyErr_Format(PyExc_IOError, "Failed to fill route cache.");
+ if (!(route_cache = fill_route_cache())) {
return NULL;
}
@@ -464,10 +480,7 @@
}
}
}
-
nl_cache_free(route_cache);
- nl_close(nls);
- nl_socket_free(nls);
return res;
}
@@ -522,7 +535,7 @@
return NULL;
}
- /* store nexthop data from our list in the structure during the update. */
+ /* Store nexthop data from our list in the structure during the update. */
for (i=0; i < PyList_GET_SIZE(route->nexthops); i++) {
Nexthop *nexthop = (Nexthop*) PyList_GET_ITEM(route->nexthops, i);
if (!PyObject_TypeCheck(nexthop, &NexthopType)) {
@@ -530,18 +543,47 @@
err = 1;
goto done;
}
- rtnl_route_add_nexthop(route->u.r, ((Nexthop*)nexthop)->nh); // borrow ref
+ nh = rtnl_route_nh_clone(((Nexthop*)nexthop)->nh);
+ if (!nh) {
+ PyErr_Format(PyExc_IOError, "Error cloning nexthop struct");
+ err = 1;
+ goto done;
+ }
+ rtnl_route_add_nexthop(route->u.r, nh);
}
- if ((err = rtnl_route_add(nls, (route)->u.r, 0)) != 0) {
+ if ((err = rtnl_route_add(nls, (route)->u.r, 0))) {
PyErr_Format(PyExc_IOError, "Route could not be added: %s", nl_geterror(err));
+ goto done;
+ }
+
+ if ((err = (sync_route(route) != 0)) != 0) {
+ goto done;
+ }
+
+ /* Refresh nexthop data from the newly synced route. */
+ if (PyList_GET_SIZE(route->nexthops) != rtnl_route_get_nnexthops(route->u.r)) {
+ PyErr_Format(PyExc_IOError, "Unexpected misalignment of route nexthops");
err = 1;
goto done;
}
+ for (i=0; i < PyList_GET_SIZE(route->nexthops); i++) {
+ Nexthop *nexthop = (Nexthop*) PyList_GET_ITEM(route->nexthops, i);
+ nh = rtnl_route_nh_clone(rtnl_route_nexthop_n(route->u.r, i));
+ if (!nh) {
+ PyErr_Format(PyExc_IOError, "Error cloning nexthop struct");
+ err = 1;
+ goto done;
+ }
+ rtnl_route_nh_free(nexthop->nh);
+ nexthop->family = rtnl_route_get_family(route->u.r);
+ nexthop->nh = nh;
+ }
done:
while ((nh = rtnl_route_nexthop_n(route->u.r, 0))) {
rtnl_route_remove_nexthop(route->u.r, nh);
+ rtnl_route_nh_free(nh);
}
nl_close(nls);
nl_socket_free(nls);
@@ -552,6 +594,51 @@
Py_RETURN_NONE;
}
+/* Sync the internal info of a route from the kernel. */
+static int sync_route(Route *route)
+{
+ struct nl_object *x;
+ struct nl_cache *route_cache = fill_route_cache();
+ int found = 0;
+ struct nl_dump_params params = {
+ .dp_fd = stdout,
+ .dp_type = NL_DUMP_DETAILS,
+ };
+
+ if (!route_cache) {
+ return -1;
+ }
+
+ fprintf(stderr, "My route:\n");
+ nl_object_dump(route->u.nlo, ¶ms);
+ for (x = nl_cache_get_first(route_cache); x; x = nl_cache_get_next(x)) {
+ struct rtnl_nexthop *nh_a = rtnl_route_nexthop_n((struct rtnl_route *)x, 0);
+ struct rtnl_nexthop *nh_b = rtnl_route_nexthop_n(route->u.r, 0);
+ fprintf(stderr, "Test route:\n");
+ nl_object_dump(x, ¶ms);
+ fprintf(stderr, "DIFF: %x\n", nl_object_diff(x, route->u.nlo));
+ fprintf(stderr, "NH DIFF: %x\n", rtnl_route_nh_compare(nh_a, nh_b, nh_b->ce_mask, 1));
+ if (nl_object_match_filter(x, route->u.nlo)) {
+ fprintf(stderr, "found\n\n");
+ nl_object_get(x);
+ rtnl_route_put(route->u.r);
+ route->u.nlo = x;
+ found = 1;
+ break;
+ } else {
+ fprintf(stderr, "mismatch\n\n");
+ }
+ }
+ nl_cache_free(route_cache);
+
+ if (!found) {
+ PyErr_SetString(PyExc_Exception, "Could not sync route with kernel.");
+ return -1;
+ }
+
+ return 0;
+}
+
static PyObject *del_rule(PyObject *mod, PyObject *args)
{
PyObject *rule;
diff -r 1c5d2a037d54 lib/python-cp/route.py
--- a/lib/python-cp/route.py Wed Aug 15 17:43:52 2012 -0600
+++ b/lib/python-cp/route.py Thu Aug 16 18:36:32 2012 -0600
@@ -26,7 +26,6 @@
import threading
import socket
-
protocols = {
0: 'unspecified',
1: 'icmp_redirect',
@@ -171,6 +170,10 @@
del_route(r)
except IOError as e:
pass
+ self.refresh()
+ if self.routes:
+ raise Exception("Failed to flush route table.")
+
def addRoute(self, route=None, **kwargs):
""" Add a route to this table. If the route arg is None then we will
@@ -200,17 +203,10 @@
if onlink:
nh.flags = 'onlink'
- if netmask:
- try:
- netmask = int(netmask)
- except:
- netmask = ipcalc.Network(0, netmask).mask
- ip = '%s/%d' % (ip, netmask)
+ r = Route()
+ r.dst = self._dstTranslate(ip, netmask)
+ r.nexthops.append(nh)
- r = Route()
- if ip:
- r.dst = ip
- r.nexthops.append(nh)
return r
def removeRoute(self, route):
@@ -218,18 +214,14 @@
del_route(route)
self.routes.remove(route)
- def getRoute(self, ip=None, netmask=None, gw=None, iface=None):
+ def getRoute(self, ip=None, netmask=None):
- self.refresh()
- for r in self.routes:
- try:
- netmask = int(netmask)
- except:
- netmask = ipcalc.Network(0, netmask).mask
- ip = '%s/%d' % (ip, netmask)
- if r.dst == ip:
- return r
-
+ dst = self._dstTranslate(ip, netmask)
+ with self.lock:
+ self.refresh()
+ for r in self.routes:
+ if r.dst == dst:
+ return r
return None
def getRoutes(self):
@@ -237,6 +229,25 @@
self.refresh()
return self.routes[:]
+ def _dstTranslate(self, ip, netmask=None):
+ """ Linux's routing/libnl-route system is a bit funny when it comes
+ to default routes. We can send them a dst of 0.0.0.0/0 and the kernel will
+ mangle that into an empty addr when we look at the route again. This
+ makes it difficult to do things like find a route that you just
+ added. """
+
+ if netmask:
+ netmask = ipcalc.Network(0, netmask).mask
+ ip = '%s/%d' % (ip, netmask)
+
+ if ip not in ('default', 'any', 'all'):
+ n = ipcalc.Network(ip)
+ if not n.ip + n.mask:
+ ip = '0.0.0.0'
+ else:
+ ip = '0.0.0.0'
+
+ return ip
class Rule(RuleBase):
diff -r 1c5d2a037d54 service_manager/services/racoon.py
--- a/service_manager/services/racoon.py Wed Aug 15 17:43:52 2012 -0600
+++ b/service_manager/services/racoon.py Thu Aug 16 18:36:32 2012 -0600
@@ -44,11 +44,10 @@
serialize = serializ.Serializable.serialize
-# NOTE, this is documented using the sphinx syntax: http://sphinx.pocoo.org/rest.html
class Racoon(serializ.Serializable, services.Service):
"""Racoon, Internet Key Exchange (IKE) daemon for automatically keying IPsec connections
- `IPsec tools` `_
- """
+ IPsec tools """
+
name = 'racoon'
__startup__ = 75
@@ -106,10 +105,18 @@
self.enableRacoon(None, self.cStore.get('config.vpn.enabled', eventing=False), booting=True)
- def onStop(self):
-
- self.freeRules()
-
+ @serialize
+ def wait(self, seconds):
+ return self.wait2(seconds)
+
+ @serialize
+ def wait2(self, x):
+ print("2START")
+ import time
+ time.sleep(seconds)
+ print("2DONE")
+
+
@serialize
def __startTunnel(self, path, cfg):
@@ -277,16 +284,27 @@
def start(self):
""" Update the config files and start the racoon daemon. """
+
+ import threading
+ t = str(threading.currentThread())
+ logger.info("STARTING RACOON: %s" % t)
+
+
if not self.enabled:
+ logger.warning("NOT ENABELD")
return
if not self.updateConfig():
logger.warning("No suitable interface found. VPN service not running.")
self.running = False
+ logger.warning("NOT SUITABLE ENABELD")
return
+ logger.info("STEP 1: %s" % t)
self.addRules()
+ logger.info("STEP 2: %s" % t)
self.addRoutes()
+ logger.info("STEP 3: %s" % t)
cmdArgs = ['-f', PATH_IPSEC, PATH_CONFIG_FILE]
cmd = self._racoon_cmd
@@ -298,8 +316,11 @@
#subprocess.call(["/sbin/sysctl", "-q", "-w", "net.inet.ipsec.active=1"])
+ logger.info("STEP 4: %s" % t)
self.procMon.setCmd(cmd)
+ logger.info("STEP 5: %s" % t)
self.procMon.start()
+ logger.info("STEP 6: %s" % t)
self.resolveGatewaysId = self.loopedTask.add(self.resolveGateways, self.resolveGatewaysTimer)
@@ -308,10 +329,14 @@
self.running = True
+ logger.info("STEP 7: %s" % t)
+ logger.info("STARTED RACOON")
+
@serialize
def stop(self):
""" Stop a running racoon daemon. """
+ logger.info("STOPING RACOON")
self.running = False
vpn_config = self.cStore.get('config.vpn', eventing=False) or {}
adv_config = vpn_config.get('adv_settings', {})
@@ -328,15 +353,18 @@
os.system("setkey -F; setkey -FP")
self.procMon.stop()
+ logger.info("IS STOPPED RACOON")
@serialize
def refresh(self, *na):
+ logger.info("Doing REFRESH")
if self.running:
self.stop()
if self.enabled and self.wanmgr.findDevices(state='connected'):
self.start()
+ logger.info("DONE REFRESH")
def addRoutes(self):
""" This will allow traffic originating from the router to go through the tunnel if the
@@ -345,14 +373,20 @@
We also add an explicit route for the remote gateway so we can force tunnel binding
out a particular wan when WAN binding is used. """
+ import threading
+ t = str(threading.currentThread())
+ logger.info("R STEP 1: %s" % t)
for tun in self.config_map.values():
+ logger.info("R STEP 2: %s" % t)
local_nets = [ ipcalc.Network(x['ip_address'], x['netmask']) for x in tun['local_network'] ]
local_router_ips = [ (x.ip_address in xx and x.ip_address) \
for x in self.lanmgr.networks \
for xx in local_nets ]
if not any(local_router_ips):
+ logger.info("R STEP 2:b %s" % t)
continue
+ logger.info("R STEP 3 %s" % t)
for r in tun['remote_network']:
ip = r.get('ip_address')
@@ -360,13 +394,20 @@
gw = local_router_ips[0]
if ip != '0.0.0.0':
try:
+ logger.info("R STEP 4: %s" % t)
self.routeTable.addRoute(ip=ip, netmask=netmask, gw=gw)
+ logger.info("R STEP 4b: %s" % t)
except Exception as e:
+ logger.info("R STEP 4c: %s" % t)
logger.warn("Route IP: %s Mask: %s GW: %s could not be added to table. %s", ip, netmask, gw, e)
+ logger.info("R STEP 5: %s" % t)
logger.info("Adding route IP:%s Mask:%s GW:%s", ip, netmask, gw)
+ logger.info("R STEP 6: %s" % t)
self.routeTable.addRoute(ip=tun['remote_gw_resolved'], gw=tun['wans'][0].ip_address)
+ logger.info("R STEP 6b: %s" % t)
+ logger.info("R STEP 7: %s" % t)
def removeRoutes(self):
@@ -378,21 +419,29 @@
self.gw_set = xtables.IPSet('gw_ipsec', 'hash:ip')
self.net_set = xtables.IPSet('net_ipsec', 'hash:net')
- """ Allow remote uses access to local LAN services. """
+ # Allow remote user access to local LAN services.
with nf.getChain('filter', 'LAN_SERVERS') as chain:
self.lan_hook = chain.addRule(nf.AcceptRule(match=nf.SetMatch('src', 'net_ipsec')))
with nf.getChain('filter', 'WAN_SERVERS') as chain:
self.esp_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_ESP,
- match=nf.SetMatch('src', 'gw_ipsec')))
+ match=nf.SetMatch('src', 'gw_ipsec')))
+ self.anon_esp_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_ESP,
+ enabled=False))
self.ike_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_UDP,
- match=nf.SetMatch('src', 'gw_ipsec'),
- triggers=IKEPortTrigger))
+ match=nf.SetMatch('src', 'gw_ipsec'),
+ triggers=IKEPortTrigger))
+ self.anon_ike_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_UDP,
+ triggers=IKEPortTrigger,
+ enabled=False))
self.natt_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_UDP,
- match=nf.SetMatch('src', 'gw_ipsec'),
- triggers=NATTPortTrigger))
+ match=nf.SetMatch('src', 'gw_ipsec'),
+ triggers=NATTPortTrigger))
+ self.anon_natt_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_UDP,
+ triggers=NATTPortTrigger,
+ enabled=False))
self.in_hook = nf.getChain('filter', 'FORWARD').addRule({
'priority': 1,
@@ -416,53 +465,34 @@
def addRules(self):
- if self.anonymousCheck():
- with nf.getChain('filter', 'WAN_SERVERS') as chain:
- chain.removeRule(self.esp_hook)
- chain.removeRule(self.ike_hook)
- chain.removeRule(self.natt_hook)
- self.esp_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_ESP))
- self.ike_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_UDP, triggers=IKEPortTrigger))
- self.natt_hook = chain.addRule(nf.AcceptRule(protocol=socket.IPPROTO_UDP, triggers=NATTPortTrigger))
+ with nf.getChain('filter', 'WAN_SERVERS') as chain:
+ enabler = self.anonymousCheck()
+ self.anon_esp_hook.enabled = enabler
+ self.anon_ike_hook.enabled = enabler
+ self.anon_natt_hook.enabled = enabler
for x_tunnel in self.config_map.values():
- if x_tunnel['remote_gateway'] != '0.0.0.0':
+ if x_tunnel['remote_gateway'] != '0.0.0.0' and x_tunnel['remote_gateway'] not in self.gw_set:
self.gw_set.append(x_tunnel['remote_gateway'])
logger.info("Allowing inbound ESP %s host" % x_tunnel['remote_gateway'])
for r in x_tunnel['remote_network']:
mask = ipcalc.Network(r['ip_address'], r['netmask']).mask
- if r['ip_address'] != '0.0.0.0' and mask != 0:
- self.net_set.append('%s/%s' % (r['ip_address'], mask))
- logger.info("Allowing inbound tunnel network %s/%s" % (r['ip_address'], mask))
+ net = '%s/%s' % (r['ip_address'], mask)
+ if r['ip_address'] != '0.0.0.0' and mask != 0 and net not in self.net_set:
+ self.net_set.append(net)
+ logger.info("Allowing inbound tunnel network %s" % net)
def removeRules(self):
- for x_tunnel in self.config_map.values():
+ with nf.getChain('filter', 'WAN_SERVERS') as chain:
+ self.anon_esp_hook.enabled = False
+ self.anon_ike_hook.enabled = False
+ self.anon_natt_hook.enabled = False
- if x_tunnel['remote_gateway'] != '0.0.0.0':
- self.gw_set.remove(x_tunnel['remote_gateway'])
- logger.info("Denying inbound ESP %s host" % x_tunnel['remote_gateway'])
-
- for r in x_tunnel['remote_network']:
- mask = ipcalc.Network(r['ip_address'], r['netmask']).mask
- if r['ip_address'] != '0.0.0.0' and mask != 0:
- self.net_set.remove('%s/%s' % (r['ip_address'], mask))
- logger.info("Removing inbound tunnel network %s/%s" % (r['ip_address'], mask))
-
- def freeRules(self):
-
- with nf.getChain('filter', 'LAN_SERVERS') as chain:
- chain.remoteRule(self.lan_hook)
-
- with nf.getChain('filter', 'WAN_SERVERS') as chain:
- chain.removeRule(self.esp_hook)
- chain.removeRule(self.ike_hook)
- chain.removeRule(self.natt_hook)
- nf.getChain('filter', 'FOWARD').removeRule(self.in_hook)
- nf.getChain('nat', 'POSTROUTING').removeRule(self.out_hook)
- self.gw_set.destroy()
+ self.gw_set.flush()
+ self.net_set.flush()
def inferIdent(self, ident):