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
+10
View File
@@ -28,6 +28,16 @@ charon.plugins.kernel-netlink.hw_offload_feature_interface = lo
cannot be used to obtain the appropriate feature flag, this option can
be used to specify an alternative interface for offload feature detection.
charon.plugins.kernel-netlink.install_routes_xfrmi = no
Whether to install routes for SAs that reference XFRM interfaces.
Whether routes via XFRM interfaces are automatically installed for SAs that
reference such an interface via _if_id_. If the traffic selectors include
the IKE traffic to the peer, this requires special care (e.g. installing
bypass policies and/or routes, or setting a mark on the IKE socket and
excluding such packets from the configured routing table via _fwmark_
option).
charon.plugins.kernel-netlink.mss = 0
MSS to set on installed routes, 0 to disable.
@@ -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),