aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c48
1 files changed, 43 insertions, 5 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
index e23cf445d..2f2167adf 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
@@ -38,6 +38,7 @@
*/
#include <sys/socket.h>
+#include <sys/utsname.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <unistd.h>
@@ -313,6 +314,11 @@ struct private_kernel_netlink_net_t {
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;
@@ -1130,11 +1136,11 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
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_DUMP;
}
hdr->nlmsg_type = RTM_GETROUTE;
@@ -1745,6 +1751,36 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
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)
{
@@ -1835,6 +1871,8 @@ kernel_netlink_net_t *kernel_netlink_net_create()
timerclear(&this->last_route_reinstall);
timerclear(&this->last_roam);
+ check_kernel_features(this);
+
if (streq(hydra->daemon, "starter"))
{ /* starter has no threads, so we do not register for kernel events */
register_for_events = FALSE;