lib->settings->set_default_str(lib->settings, "charon-nm.port", "0");
lib->settings->set_default_str(lib->settings, "charon-nm.port_nat_t", "0");
+ /* install VIPs on lo as NM might modify the physical interface (this seems
+ * to affect IPv6 in particular), it actually installs the VIPs on the
+ * passed device again, but since that happens after we require them for
+ * installing routes, we install them ourselves too */
+ lib->settings->set_default_str(lib->settings,
+ "charon-nm.install_virtual_ip_on", "lo");
+
+ /* install routes via XFRM interfaces, if we can use them */
+ lib->settings->set_default_str(lib->settings,
+ "charon-nm.plugins.kernel-netlink.install_routes_xfrmi", "yes");
+ /* bypass IKE traffic from these routes in case traffic selectors conflict */
+ lib->settings->set_default_str(lib->settings,
+ "charon-nm.plugins.socket-default.fwmark", "220");
+ lib->settings->set_default_str(lib->settings,
+ "charon-nm.plugins.kernel-netlink.fwmark", "!220");
+
DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
if (lib->integrity)
{
/*
* Copyright (C) 2017 Lubomir Rintel
- *
- * Copyright (C) 2013-2020 Tobias Brunner
+ * Copyright (C) 2013-2023 Tobias Brunner
* Copyright (C) 2008-2009 Martin Willi
*
* This program is free software; you can redistribute it and/or modify it
* for more details.
*/
+#include <stdio.h>
+#include <inttypes.h>
+#include <net/if.h>
+
#include "nm_service.h"
#include <daemon.h>
#include <config/peer_cfg.h>
#include <credentials/certificates/x509.h>
#include <networking/tun_device.h>
+#include <plugins/kernel_netlink/kernel_netlink_xfrmi.h>
-#include <stdio.h>
+#define XFRMI_DEFAULT_MTU 1400
/**
* Private data of NMStrongswanPlugin
nm_creds_t *creds;
/* attribute handler for DNS/NBNS server information */
nm_handler_t *handler;
- /* dummy TUN device */
+ /* manager for XFRM interfaces, if supported */
+ kernel_netlink_xfrmi_t *xfrmi_manager;
+ /* interface ID of XFRM interface */
+ uint32_t xfrmi_id;
+ /* name of XFRM interface if one is used */
+ char *xfrmi;
+ /* dummy TUN device if not using XFRM interface */
tun_device_t *tun;
/* name of the connection */
char *name;
return g_variant_builder_end (&builder);
}
+/**
+ * Destroy any allocated XFRM or TUN interface
+ */
+static void delete_interface(NMStrongswanPluginPrivate *priv)
+{
+ if (priv->xfrmi)
+ {
+ priv->xfrmi_manager->delete(priv->xfrmi_manager, priv->xfrmi);
+ free(priv->xfrmi);
+ priv->xfrmi = NULL;
+ }
+ if (priv->tun)
+ {
+ priv->tun->destroy(priv->tun);
+ priv->tun = NULL;
+ }
+}
+
/**
* Signal IP config to NM, set connection as established
*/
handler = priv->handler;
- /* NM apparently requires to know the gateway */
+ /* NM apparently requires to know the gateway (it uses it to install a
+ * direct route via physical interface if conflicting routes are passed) */
other = ike_sa->get_other_host(ike_sa);
g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY,
host_to_variant(other));
/* systemd-resolved requires a device to properly install DNS servers, but
- * Netkey does not use one. Passing the physical interface is not ideal,
+ * Netkey does not require one. Passing the physical interface is not ideal,
* as NM fiddles around with it and systemd-resolved likes a separate
- * device. So we pass a dummy TUN device along for NM etc. to play with...
+ * device. So we pass either an XFRM interface or a dummy TUN device along
+ * for NM etc. to play with...
*/
- DESTROY_IF(priv->tun);
- priv->tun = tun_device_create(NULL);
- if (priv->tun)
+ delete_interface(priv);
+ if (priv->xfrmi_manager && priv->xfrmi_id)
+ {
+ char name[IFNAMSIZ];
+ int mtu;
+
+ /* use the interface ID to get a unique name, fine if it's cut off */
+ snprintf(name, sizeof(name), "nm-xfrm-%" PRIu32, priv->xfrmi_id);
+ mtu = lib->settings->get_int(lib->settings, "charon-nm.mtu",
+ XFRMI_DEFAULT_MTU);
+
+ if (priv->xfrmi_manager->create(priv->xfrmi_manager, name,
+ priv->xfrmi_id, NULL, mtu))
+ {
+ priv->xfrmi = strdup(name);
+ }
+ }
+ if (!priv->xfrmi)
+ {
+ priv->tun = tun_device_create(NULL);
+ }
+ if (priv->xfrmi)
+ {
+ g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_TUNDEV,
+ g_variant_new_string (priv->xfrmi));
+ }
+ else if (priv->tun)
{
g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_TUNDEV,
g_variant_new_string (priv->tun->get_name(priv->tun)));
}
else
{
- DBG1(DBG_CFG, "failed to create dummy TUN device, might affect DNS "
- "server installation negatively");
+ DBG1(DBG_CFG, "failed to create XFRM or dummy TUN device, might affect "
+ "DNS server installation negatively");
}
/* pass the first virtual IPs we got or use the physical IP */
host_to_variant(vip4));
g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
g_variant_new_uint32 (vip4->get_address(vip4).len * 8));
-
- /* prevent NM from changing the default route. we set our own route in our
- * own routing table
- */
- g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
- g_variant_new_boolean (TRUE));
-
g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
handler_to_variant(handler, "au", INTERNAL_IP4_DNS));
-
g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
handler_to_variant(handler, "au", INTERNAL_IP4_NBNS));
+
+ /* prevent NM from changing the default route, as we set our own routes
+ * in a separate routing table
+ */
+ g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
+ g_variant_new_boolean (TRUE));
}
if (vip6)
host_to_variant(vip6));
g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX,
g_variant_new_uint32 (vip6->get_address(vip6).len * 8));
- g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
- g_variant_new_boolean (TRUE));
g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS,
handler_to_variant(handler, "aay", INTERNAL_IP6_DNS));
/* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
+
+ g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
+ g_variant_new_boolean (TRUE));
}
ip4config = g_variant_builder_end (&ip4builder);
NM_TYPE_SETTING_CONNECTION));
vpn = NM_SETTING_VPN(nm_connection_get_setting(connection,
NM_TYPE_SETTING_VPN));
+ if (priv->xfrmi_manager)
+ {
+ /* allocate a random interface ID */
+ priv->xfrmi_id = random();
+ }
if (priv->name)
{
free(priv->name);
* secrets from earlier connections) before we clear them in connect() */
priv->creds->clear(priv->creds);
- /* delete the dummy TUN device */
- if (priv->tun)
- {
- priv->tun->destroy(priv->tun);
- priv->tun = NULL;
- }
+ /* delete any allocated interface */
+ delete_interface(priv);
return FALSE;
}
priv->listener.ike_reestablish_pre = _ike_reestablish_pre;
priv->listener.ike_reestablish_post = _ike_reestablish_post;
charon->bus->add_listener(charon->bus, &priv->listener);
- priv->tun = NULL;
- priv->name = NULL;
+ priv->xfrmi_manager = lib->get(lib, KERNEL_NETLINK_XFRMI_MANAGER);
}
/**
plugin = NM_STRONGSWAN_PLUGIN(obj);
priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
- if (priv->tun)
- {
- priv->tun->destroy(priv->tun);
- priv->tun = NULL;
- }
+ delete_interface(priv);
G_OBJECT_CLASS (nm_strongswan_plugin_parent_class)->dispose (obj);
}