From 7beb31aae4e231f95366dc2ef83888e197bc693c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 18 Jun 2012 12:01:10 +0200 Subject: [PATCH] Fixed IPv6 source address lookup Because Linux kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes we didn't use NLM_F_DUMP to get all routes. Still routes installed with policies are installed also for IPv6. So since only one route is returned without DUMP, and we ignore all routes from our own routing table, no source address was found during roaming if DST of the installed route included the IKE peer. With newer kernels we can now use DUMP as we did for IPv4 already, for older kernels we do so if our own routes are installed in a separate routing table, otherwise we still use GET. --- .../plugins/kernel_netlink/kernel_netlink_net.c | 48 ++++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) Index: strongswan/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c =================================================================== --- strongswan.orig/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c 2012-06-28 21:16:07.000000000 +0200 +++ strongswan/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c 2012-07-02 17:10:51.224474221 +0200 @@ -38,6 +38,7 @@ */ #include +#include #include #include #include @@ -183,6 +184,11 @@ bool install_virtual_ip; /** + * whether preferred source addresses can be specified for IPv6 routes + */ + bool rta_prefsrc_for_ipv6; + + /** * list with routing tables to be excluded from route lookup */ linked_list_t *rt_exclude; @@ -869,11 +875,11 @@ hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST; - if (dest->get_family(dest) == AF_INET) - { - /* We dump all addresses for IPv4, as we want to ignore IPsec specific - * routes installed by us. But the kernel does not return source - * addresses in a IPv6 dump, so fall back to get() for v6 routes. */ + if (dest->get_family(dest) == AF_INET || this->rta_prefsrc_for_ipv6 || + this->routing_table) + { /* kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes. + * as we want to ignore routes with virtual IPs we cannot use DUMP + * if these routes are not installed in a separate table */ hdr->nlmsg_flags |= NLM_F_ROOT | NLM_F_DUMP; } hdr->nlmsg_type = RTM_GETROUTE; @@ -1443,6 +1449,36 @@ return this->socket->send_ack(this->socket, hdr); } +/** + * check for kernel features (currently only via version number) + */ +static void check_kernel_features(private_kernel_netlink_net_t *this) +{ + struct utsname utsname; + int a, b, c; + + if (uname(&utsname) == 0) + { + switch(sscanf(utsname.release, "%d.%d.%d", &a, &b, &c)) + { + case 3: + if (a == 2) + { + DBG2(DBG_KNL, "detected Linux %d.%d.%d, no support for " + "RTA_PREFSRC for IPv6 routes", a, b, c); + break; + } + /* fall-through */ + case 2: + /* only 3.x+ uses two part version numbers */ + this->rta_prefsrc_for_ipv6 = TRUE; + break; + default: + break; + } + } +} + METHOD(kernel_net_t, destroy, void, private_kernel_netlink_net_t *this) { @@ -1509,6 +1545,8 @@ ); timerclear(&this->last_roam); + check_kernel_features(this); + exclude = lib->settings->get_str(lib->settings, "%s.ignore_routing_tables", NULL, hydra->daemon); if (exclude)