kernel-netlink: Add an option to install routes for SAs with XFRM interfaces

Since these might conflict with IKE traffic, this requires special care.
One option is to install bypass policies for the peer, which install
appropriate (throw) routes.  However, that won't work if the traffic to
the gateway itself should be protected, in particular, for host-to-host
tunnels.  So an alternative is to set a mark for the IKE socket and then
exclude that traffic from table 220 via the kernel-netlink plugin's
fwmark option.
This commit is contained in:
Tobias Brunner
2023-02-22 13:37:45 +01:00
parent 0cc780d317
commit 04486507b2
2 changed files with 56 additions and 7 deletions
@@ -358,6 +358,11 @@ struct private_kernel_netlink_ipsec_t {
*/
bool install_routes;
/**
* Whether to install routes via XFRM interfaces
*/
bool install_routes_xfrmi;
/**
* Whether to set protocol and ports on selector installed with transport
* mode IPsec SAs
@@ -2736,6 +2741,30 @@ static void policy_change_done(private_kernel_netlink_ipsec_t *this,
this->mutex->unlock(this->mutex);
}
/**
* Find an XFRM interface with the given ID
*/
static bool find_xfrmi(private_kernel_netlink_ipsec_t *this, uint32_t target,
char **if_name)
{
enumerator_t *enumerator;
char *name;
uint32_t if_id;
enumerator = this->xfrmi->create_enumerator(this->xfrmi);
while (enumerator->enumerate(enumerator, &name, &if_id, NULL, NULL))
{
if (if_id == target)
{
*if_name = strdup(name);
enumerator->destroy(enumerator);
return TRUE;
}
}
enumerator->destroy(enumerator);
return FALSE;
}
/**
* Install a route for the given policy if enabled and required
*/
@@ -2765,9 +2794,15 @@ static void install_route(private_kernel_netlink_ipsec_t *this,
if (!ipsec->dst->is_anyaddr(ipsec->dst))
{
route->gateway = charon->kernel->get_nexthop(charon->kernel,
ipsec->dst, -1, ipsec->src,
&route->if_name);
/* if if_ids are used, install a route via XFRM interface if any,
* otherwise install the route via the interface we reach the peer */
if (!policy->if_id || !this->xfrmi ||
!find_xfrmi(this, policy->if_id, &route->if_name))
{
route->gateway = charon->kernel->get_nexthop(charon->kernel,
ipsec->dst, -1, ipsec->src,
&route->if_name);
}
}
else
{ /* for shunt policies */
@@ -3006,12 +3041,12 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
* - this is an outbound policy (to just get one for each child)
* - routing is not disabled via strongswan.conf
* - the selector is not for a specific protocol/port
* - no XFRM interface ID is configured
* - routes via XFRM interfaces are enabled or no interface ID is configured
* - we are in tunnel/BEET mode or install a bypass policy
*/
if (policy->direction == POLICY_OUT && this->install_routes &&
!policy->sel.proto && !policy->sel.dport && !policy->sel.sport &&
!policy->if_id)
(this->install_routes_xfrmi || !policy->if_id))
{
if (mapping->type == POLICY_PASS ||
(mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT))
@@ -4148,9 +4183,13 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
.get_priority = dlsym(RTLD_DEFAULT,
"kernel_netlink_get_priority_custom"),
.policy_update = lib->settings->get_bool(lib->settings,
"%s.plugins.kernel-netlink.policy_update", FALSE, lib->ns),
"%s.plugins.kernel-netlink.policy_update",
FALSE, lib->ns),
.install_routes = lib->settings->get_bool(lib->settings,
"%s.install_routes", TRUE, lib->ns),
"%s.install_routes", TRUE, lib->ns),
.install_routes_xfrmi = lib->settings->get_bool(lib->settings,
"%s.plugins.kernel-netlink.install_routes_xfrmi",
FALSE, lib->ns),
.proto_port_transport = lib->settings->get_bool(lib->settings,
"%s.plugins.kernel-netlink.set_proto_port_transport_sa",
FALSE, lib->ns),