kernel-netlink: Optionally trigger roam events on routing rule changes

This can be useful if routing rules (instead of e.g. route metrics) are used
to switch from one to another interface (i.e. from one to another
routing table).  Since we currently don't evaluate routing rules when
doing the route lookup this is only useful if the kernel-based route
lookup is used.

Resolves strongswan/strongswan#88.
This commit is contained in:
Tobias Brunner 2018-01-29 15:26:17 +01:00
parent 80ae474863
commit 4664992f7d
2 changed files with 77 additions and 3 deletions

View File

@ -47,6 +47,13 @@ charon.plugins.kernel-netlink.port_bypass = no
port based policies use global XFRM bypass policies for the used IKE UDP
ports.
charon.plugins.kernel-netlink.process_rules = no
Whether to process changes in routing rules to trigger roam events.
Whether to process changes in routing rules to trigger roam events. This is
currently only useful if the kernel based route lookup is used (i.e. if
route installation is disabled or an inverted fwmark match is configured).
charon.plugins.kernel-netlink.receive_buffer_size = 0
Maximum Netlink socket receive buffer in bytes.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2016 Tobias Brunner
* Copyright (C) 2008-2018 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@ -78,6 +78,9 @@
#define ROUTING_TABLE_PRIO 0
#endif
/** multicast groups (for groups > 31 setsockopt has to be used) */
#define nl_group(group) (1 << (group - 1))
ENUM(rt_msg_names, RTM_NEWLINK, RTM_GETRULE,
"RTM_NEWLINK",
"RTM_DELLINK",
@ -472,6 +475,11 @@ struct private_kernel_netlink_net_t {
*/
bool process_route;
/**
* whether to react to RTM_NEWRULE or RTM_DELRULE events
*/
bool process_rules;
/**
* whether to trigger roam events
*/
@ -1451,6 +1459,45 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h
host->destroy(host);
}
/**
* process RTM_NEW|DELRULE from kernel
*/
static void process_rule(private_kernel_netlink_net_t *this, struct nlmsghdr *hdr)
{
#ifdef HAVE_LINUX_FIB_RULES_H
struct rtmsg* msg = NLMSG_DATA(hdr);
struct rtattr *rta = RTM_RTA(msg);
size_t rtasize = RTM_PAYLOAD(hdr);
uint32_t table = 0;
/* ignore rules added by us or in the local routing table (local addrs) */
if (msg->rtm_table && (msg->rtm_table == this->routing_table ||
msg->rtm_table == RT_TABLE_LOCAL))
{
return;
}
while (RTA_OK(rta, rtasize))
{
switch (rta->rta_type)
{
case FRA_TABLE:
if (RTA_PAYLOAD(rta) == sizeof(table))
{
table = *(uint32_t*)RTA_DATA(rta);
}
break;
}
rta = RTA_NEXT(rta, rtasize);
}
if (table && table == this->routing_table)
{ /* also check against extended table ID */
return;
}
fire_roam_event(this, FALSE);
#endif
}
/**
* Receives events from kernel
*/
@ -1508,6 +1555,13 @@ static bool receive_events(private_kernel_netlink_net_t *this, int fd,
process_route(this, hdr);
}
break;
case RTM_NEWRULE:
case RTM_DELRULE:
if (this->process_rules)
{
process_rule(this, hdr);
}
break;
default:
break;
}
@ -2985,6 +3039,8 @@ kernel_netlink_net_t *kernel_netlink_net_create()
"%s.prefer_temporary_addrs", FALSE, lib->ns),
.roam_events = lib->settings->get_bool(lib->settings,
"%s.plugins.kernel-netlink.roam_events", TRUE, lib->ns),
.process_rules = lib->settings->get_bool(lib->settings,
"%s.plugins.kernel-netlink.process_rules", FALSE, lib->ns),
.mtu = lib->settings->get_int(lib->settings,
"%s.plugins.kernel-netlink.mtu", 0, lib->ns),
.mss = lib->settings->get_int(lib->settings,
@ -3037,8 +3093,19 @@ kernel_netlink_net_t *kernel_netlink_net_create()
destroy(this);
return NULL;
}
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK;
addr.nl_groups = nl_group(RTNLGRP_IPV4_IFADDR) |
nl_group(RTNLGRP_IPV6_IFADDR) |
nl_group(RTNLGRP_LINK);
if (this->process_route)
{
addr.nl_groups |= nl_group(RTNLGRP_IPV4_ROUTE) |
nl_group(RTNLGRP_IPV6_ROUTE);
}
if (this->process_rules)
{
addr.nl_groups |= nl_group(RTNLGRP_IPV4_RULE) |
nl_group(RTNLGRP_IPV6_RULE);
}
if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr)))
{
DBG1(DBG_KNL, "unable to bind RT event socket: %s (%d)",