diff options
author | Tobias Brunner <tobias@strongswan.org> | 2011-12-20 14:30:10 +0100 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2012-05-02 14:56:08 +0200 |
commit | 74ba22c99233d183da5e424e55e82382dfa26341 (patch) | |
tree | 762b198958add8db7eeec94052088b22bb6389b4 /src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c | |
parent | d55c240474668f7db8c4692281a7142dd1e84ca7 (diff) | |
download | strongswan-74ba22c99233d183da5e424e55e82382dfa26341.tar.bz2 strongswan-74ba22c99233d183da5e424e55e82382dfa26341.tar.xz |
Keep track of installed source routes in kernel-netlink plugin.
Diffstat (limited to 'src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c')
-rw-r--r-- | src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c | 149 |
1 files changed, 141 insertions, 8 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c index cce0ff402..2835f5b02 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008-2011 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -116,6 +116,77 @@ static void iface_entry_destroy(iface_entry_t *this) free(this); } +typedef struct route_entry_t route_entry_t; + +/** + * Installed routing entry + */ +struct route_entry_t { + /** Name of the interface the route is bound to */ + char *if_name; + + /** Source ip of the route */ + host_t *src_ip; + + /** Gateway for this route */ + host_t *gateway; + + /** Destination net */ + chunk_t dst_net; + + /** Destination net prefixlen */ + u_int8_t prefixlen; +}; + +/** + * Clone a route_entry_t object. + */ +static route_entry_t *route_entry_clone(route_entry_t *this) +{ + route_entry_t *route; + + INIT(route, + .if_name = strdup(this->if_name), + .src_ip = this->src_ip->clone(this->src_ip), + .gateway = this->gateway->clone(this->gateway), + .dst_net = chunk_clone(this->dst_net), + .prefixlen = this->prefixlen, + ); + return route; +} + +/** + * Destroy a route_entry_t object + */ +static void route_entry_destroy(route_entry_t *this) +{ + free(this->if_name); + DESTROY_IF(this->src_ip); + DESTROY_IF(this->gateway); + chunk_free(&this->dst_net); + free(this); +} + +/** + * Hash a route_entry_t object + */ +static u_int route_entry_hash(route_entry_t *this) +{ + return chunk_hash_inc(chunk_from_thing(this->prefixlen), + chunk_hash(this->dst_net)); +} + +/** + * Compare two route_entry_t objects + */ +static bool route_entry_equals(route_entry_t *a, route_entry_t *b) +{ + return a->if_name && b->if_name && streq(a->if_name, b->if_name) && + a->src_ip->equals(a->src_ip, b->src_ip) && + a->gateway->equals(a->gateway, b->gateway) && + chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen; +} + typedef struct private_kernel_netlink_net_t private_kernel_netlink_net_t; /** @@ -173,6 +244,11 @@ struct private_kernel_netlink_net_t { int routing_table_prio; /** + * installed routes + */ + hashtable_t *routes; + + /** * whether to react to RTM_NEWROUTE or RTM_DELROUTE events */ bool process_route; @@ -1240,9 +1316,10 @@ METHOD(kernel_net_t, del_ip, status_t, * Manages source routes in the routing table. * By setting the appropriate nlmsg_type, the route gets added or removed. */ -static status_t manage_srcroute(private_kernel_netlink_net_t *this, int nlmsg_type, - int flags, chunk_t dst_net, u_int8_t prefixlen, - host_t *gateway, host_t *src_ip, char *if_name) +static status_t manage_srcroute(private_kernel_netlink_net_t *this, + int nlmsg_type, int flags, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, + host_t *src_ip, char *if_name) { netlink_buf_t request; struct nlmsghdr *hdr; @@ -1306,16 +1383,56 @@ METHOD(kernel_net_t, add_route, status_t, private_kernel_netlink_net_t *this, chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name) { - return manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, - dst_net, prefixlen, gateway, src_ip, if_name); + status_t status; + route_entry_t *found, route = { + .dst_net = dst_net, + .prefixlen = prefixlen, + .gateway = gateway, + .src_ip = src_ip, + .if_name = if_name, + }; + + this->mutex->lock(this->mutex); + found = this->routes->get(this->routes, &route); + if (found) + { + this->mutex->unlock(this->mutex); + return ALREADY_DONE; + } + found = route_entry_clone(&route); + this->routes->put(this->routes, found, found); + status = manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, + dst_net, prefixlen, gateway, src_ip, if_name); + this->mutex->unlock(this->mutex); + return status; } METHOD(kernel_net_t, del_route, status_t, private_kernel_netlink_net_t *this, chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name) { - return manage_srcroute(this, RTM_DELROUTE, 0, dst_net, prefixlen, - gateway, src_ip, if_name); + status_t status; + route_entry_t *found, route = { + .dst_net = dst_net, + .prefixlen = prefixlen, + .gateway = gateway, + .src_ip = src_ip, + .if_name = if_name, + }; + + this->mutex->lock(this->mutex); + found = this->routes->get(this->routes, &route); + if (!found) + { + this->mutex->unlock(this->mutex); + return NOT_FOUND; + } + this->routes->remove(this->routes, found); + route_entry_destroy(found); + status = manage_srcroute(this, RTM_DELROUTE, 0, dst_net, prefixlen, + gateway, src_ip, if_name); + this->mutex->unlock(this->mutex); + return status; } /** @@ -1446,6 +1563,9 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type, METHOD(kernel_net_t, destroy, void, private_kernel_netlink_net_t *this) { + enumerator_t *enumerator; + route_entry_t *route; + if (this->routing_table) { manage_rule(this, RTM_DELRULE, AF_INET, this->routing_table, @@ -1462,6 +1582,17 @@ METHOD(kernel_net_t, destroy, void, close(this->socket_events); } DESTROY_IF(this->socket); + + enumerator = this->routes->create_enumerator(this->routes); + while (enumerator->enumerate(enumerator, NULL, (void**)&route)) + { + manage_srcroute(this, RTM_DELROUTE, 0, route->dst_net, route->prefixlen, + route->gateway, route->src_ip, route->if_name); + route_entry_destroy(route); + } + enumerator->destroy(enumerator); + this->routes->destroy(this->routes); + this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy); this->rt_exclude->destroy(this->rt_exclude); this->condvar->destroy(this->condvar); @@ -1495,6 +1626,8 @@ kernel_netlink_net_t *kernel_netlink_net_create() }, .socket = netlink_socket_create(NETLINK_ROUTE), .rt_exclude = linked_list_create(), + .routes = hashtable_create((hashtable_hash_t)route_entry_hash, + (hashtable_equals_t)route_entry_equals, 16), .ifaces = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), |