From 04486507b212c1b0850e231ad4c120f518e2c1dd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 9 Jan 2023 15:10:55 +0100 Subject: [PATCH] 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. --- conf/plugins/kernel-netlink.opt | 10 ++++ .../kernel_netlink/kernel_netlink_ipsec.c | 53 ++++++++++++++++--- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/conf/plugins/kernel-netlink.opt b/conf/plugins/kernel-netlink.opt index 1ca5a42ddd..f1767ef34c 100644 --- a/conf/plugins/kernel-netlink.opt +++ b/conf/plugins/kernel-netlink.opt @@ -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. diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 229d9d7188..35fd7bd6cf 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -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), -- 2.47.2