aboutsummaryrefslogtreecommitdiffstats
path: root/src/libhydra/plugins/kernel_netlink
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2011-09-01 11:33:13 +0200
committerTobias Brunner <tobias@strongswan.org>2012-09-21 18:16:25 +0200
commitda6d86dd94b9ab6611a2318aa08325d9e9182431 (patch)
treee087403b74cb822311e9dc20e62d6f2e321b3ce8 /src/libhydra/plugins/kernel_netlink
parent6676769e8c686f9eba5f82ef83a9300d97187eec (diff)
downloadstrongswan-da6d86dd94b9ab6611a2318aa08325d9e9182431.tar.bz2
strongswan-da6d86dd94b9ab6611a2318aa08325d9e9182431.tar.xz
Try to keep the given source address when looking up routes
This allows to pin the local end of an IKE_SA to an address that is not the physical address of an interface. Without this patch the local address would change to the physical address when roam events occur.
Diffstat (limited to 'src/libhydra/plugins/kernel_netlink')
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
index 91d29eb34..d845a0f02 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
@@ -466,10 +466,12 @@ static int get_vip_refcount(private_kernel_netlink_net_t *this, host_t* ip)
/**
* get the first non-virtual ip address on the given interface.
+ * if a candidate address is given, we first search for that address and if not
+ * found return the address as above.
* returned host is a clone, has to be freed by caller.
*/
static host_t *get_interface_address(private_kernel_netlink_net_t *this,
- int ifindex, int family)
+ int ifindex, int family, host_t *candidate)
{
enumerator_t *ifaces, *addrs;
iface_entry_t *iface;
@@ -485,10 +487,23 @@ static host_t *get_interface_address(private_kernel_netlink_net_t *this,
addrs = iface->addrs->create_enumerator(iface->addrs);
while (addrs->enumerate(addrs, &addr))
{
- if (!addr->virtual && addr->ip->get_family(addr->ip) == family)
+ if (addr->virtual)
{
- ip = addr->ip->clone(addr->ip);
- break;
+ continue;
+ }
+ if (addr->ip->get_family(addr->ip) == family)
+ {
+ if (!candidate || candidate->ip_equals(candidate, addr->ip))
+ { /* stop at the first address if we don't search for a
+ * candidate or if the candidate matches */
+ ip = addr->ip;
+ break;
+ }
+ else if (!ip)
+ { /* store the first address as fallback if candidate is
+ * not found */
+ ip = addr->ip;
+ }
}
}
addrs->destroy(addrs);
@@ -496,6 +511,10 @@ static host_t *get_interface_address(private_kernel_netlink_net_t *this,
}
}
ifaces->destroy(ifaces);
+ if (ip)
+ {
+ ip = ip->clone(ip);
+ }
this->mutex->unlock(this->mutex);
return ip;
}
@@ -815,7 +834,7 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h
}
if (!host && rta_oif)
{
- host = get_interface_address(this, rta_oif, msg->rtm_family);
+ host = get_interface_address(this, rta_oif, msg->rtm_family, NULL);
}
if (host)
{
@@ -1161,6 +1180,13 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
for (current = out; NLMSG_OK(current, len);
current = NLMSG_NEXT(current, len))
{
+ if (!nexthop && candidate && src && src->ip_equals(src, candidate))
+ { /* if we found a route that includes our preferred source address
+ * we stop looking for any other routes. this is mainly for the
+ * DUMP cases as there the RTA_PREFSRC attribute has no effect */
+ break;
+ }
+
switch (current->nlmsg_type)
{
case NLMSG_DONE:
@@ -1271,7 +1297,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
if (rta_oif)
{ /* no src or gtw, but an interface. Get address from it. */
new_src = get_interface_address(this, rta_oif,
- msg->rtm_family);
+ msg->rtm_family, candidate);
if (new_src)
{
DESTROY_IF(src);