From: Simon Tatham Date: Tue, 27 Nov 2012 19:10:24 +0000 (+0000) Subject: tun: add hard routes even if they are currently down. X-Git-Tag: debian/0.3.0_beta2~44 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=commitdiff_plain;h=efacf9e0049ac05c817a88158d0cce5ea9d81b09 tun: add hard routes even if they are currently down. If a netlink is configured with OPT_SOFTROUTE, we expect to be adding and removing the kernel routing table entry as the remote site appears and disappears, so tun_set_route should bring the route up or down depending on route->up. However, if it isn't, then we won't be doing that during PHASE_RUN, and therefore we should bring the route up once and for all at startup. Previously the state was as follows: secnet's 'tun' netlink will add and remove kernel routing table entries during PHASE_RUN if the OPT_SOFTROUTE option is set. However, at startup during PHASE_GETRESOURCES it will set up routes for a site only if that site lists an address. So if you have a site in your sites file with no address but also haven't enabled OPT_SOFTROUTE (e.g. because you run secnet so that it drops privs), then no route for that site will _ever_ be set up. These two policies don't match. We should bring a site's route(s) up at startup in any situation where we will not be prepared to do so dynamically during run time. In other words, routes should be added at startup time not only if they have a fixed address parameter, but also if they do not have OPT_SOFTROUTE set. (See also 04f92904ea6c41517ff7154910c16ef4c3bc646b, which seems to be fixing the analogous bug for userv-ipif. [ bdd4351ff2fc6dc8b1dad689f751ac46347636cf which seems to be the relevant later commit is in fact empty -iwj. ] This commit implements this fix, and causes my home secnet implementation to be able to route to my laptop successfully (sgo/resolution/resolution). In order to do this I've had to move the definition of OPT_SOFTROUTE out of netlink.c into netlink.h so that tun_set_route can see it, which suggests a possible layering violation, but on the other hand since the netlink_client structure is visible outside netlink.c it seems only reasonable that the bit flags used in its 'options' field should be visible too. Signed-off-by: Simon Tatham --- diff --git a/netlink.c b/netlink.c index 486df6f..b2bd224 100644 --- a/netlink.c +++ b/netlink.c @@ -106,9 +106,6 @@ their use. #include "netlink.h" #include "process.h" -#define OPT_SOFTROUTE 1 -#define OPT_ALLOWROUTE 2 - #define ICMP_TYPE_ECHO_REPLY 0 #define ICMP_TYPE_UNREACHABLE 3 diff --git a/netlink.h b/netlink.h index ffefd80..a7bc9af 100644 --- a/netlink.h +++ b/netlink.h @@ -31,6 +31,10 @@ struct netlink_client { struct netlink_client *next; }; +/* options field in 'struct netlink_client' */ +#define OPT_SOFTROUTE 1 +#define OPT_ALLOWROUTE 2 + typedef bool_t netlink_route_fn(void *cst, struct netlink_client *routes); /* Netlink provides one function to the device driver, to call to deliver diff --git a/tun.c b/tun.c index 0baaf12..b0bde38 100644 --- a/tun.c +++ b/tun.c @@ -166,8 +166,14 @@ static bool_t tun_set_route(void *sst, struct netlink_client *routes) struct subnet_list *nets; int32_t i; int fd=-1; + bool_t up; - if (routes->up == routes->kup) return False; + if (routes->options & OPT_SOFTROUTE) + up = routes->up; + else + up = routes->link_quality > LINK_QUALITY_UNUSED; + + if (up == routes->kup) return False; if (st->route_type==TUN_CONFIG_IOCTL) { if (st->tun_flavour==TUN_FLAVOUR_STREAMS) { fd=open(st->ip_path,O_RDWR); @@ -187,20 +193,20 @@ static bool_t tun_set_route(void *sst, struct netlink_client *routes) network=ipaddr_to_string(nets->list[i].prefix); mask=ipaddr_to_string(nets->list[i].mask); Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n", - st->nl.name,routes->up?"adding":"deleting",network, - nets->list[i].len,routes->up?"to":"from"); + st->nl.name,up?"adding":"deleting",network, + nets->list[i].len,up?"to":"from"); switch (st->route_type) { case TUN_CONFIG_LINUX: - sys_cmd(st->route_path,"route",routes->up?"add":"del", + sys_cmd(st->route_path,"route",up?"add":"del", "-net",network,"netmask",mask, "gw",secnetaddr,(char *)0); break; case TUN_CONFIG_BSD: - sys_cmd(st->route_path,"route",routes->up?"add":"del", + sys_cmd(st->route_path,"route",up?"add":"del", "-net",network,secnetaddr,mask,(char *)0); break; case TUN_CONFIG_SOLARIS25: - sys_cmd(st->route_path,"route",routes->up?"add":"del", + sys_cmd(st->route_path,"route",up?"add":"del", network,secnetaddr,(char *)0); break; case TUN_CONFIG_IOCTL: @@ -222,7 +228,7 @@ static bool_t tun_set_route(void *sst, struct netlink_client *routes) sa->sin_family=AF_INET; sa->sin_addr.s_addr=htonl(st->nl.secnet_address); rt.rt_flags=RTF_UP|RTF_GATEWAY; - action=routes->up?SIOCADDRT:SIOCDELRT; + action=up?SIOCADDRT:SIOCDELRT; if (ioctl(fd,action,&rt)<0) { fatal_perror("tun_set_route: ioctl()"); } @@ -241,7 +247,7 @@ static bool_t tun_set_route(void *sst, struct netlink_client *routes) if (st->route_type==TUN_CONFIG_IOCTL) { close(fd); } - routes->kup=routes->up; + routes->kup=up; return True; }