diff --git a/conf/plugins/kernel-netlink.opt b/conf/plugins/kernel-netlink.opt index 1ca5a42dd..f1767ef34 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 229d9d718..35fd7bd6c 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),