]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-netlink: Add an option to install routes for SAs with XFRM interfaces
authorTobias Brunner <tobias@strongswan.org>
Mon, 9 Jan 2023 14:10:55 +0000 (15:10 +0100)
committerTobias Brunner <tobias@strongswan.org>
Wed, 22 Feb 2023 12:37:45 +0000 (13:37 +0100)
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
src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c

index 1ca5a42dddaaa9438e025854d10e186f7c9cef92..f1767ef34c0d504ed057b840036e6ed7b8a025ed 100644 (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.
 
index 229d9d7188ec3a2b78ce45f7ff6e28cba2b73097..35fd7bd6cff67d9884d9354502f6109cb157721a 100644 (file)
@@ -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),