diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 5bfb76fb4c..1857602133 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -7536,6 +7536,9 @@ static const NMMetaPropertyInfo *const property_infos_WIREGUARD[] = { .base = 16, ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_MTU, + .property_type = &_pt_gobject_mtu, + ), NULL }; diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 235a9c7f30..2bdff62d10 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -364,6 +364,7 @@ #define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.") +#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY N_("The 256 bit private-key in base64 encoding.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS N_("Flags indicating how to handle the \"private-key\" property.") #define DESCRIBE_DOC_NM_SETTING_WPAN_CHANNEL N_("IEEE 802.15.4 channel. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".") diff --git a/libnm-core/nm-setting-wireguard.c b/libnm-core/nm-setting-wireguard.c index 19b418547d..317f30f845 100644 --- a/libnm-core/nm-setting-wireguard.c +++ b/libnm-core/nm-setting-wireguard.c @@ -850,10 +850,11 @@ typedef struct { /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_FWMARK, + PROP_LISTEN_PORT, + PROP_MTU, PROP_PRIVATE_KEY, PROP_PRIVATE_KEY_FLAGS, - PROP_LISTEN_PORT, - PROP_FWMARK, ); typedef struct { @@ -862,6 +863,7 @@ typedef struct { GHashTable *peers_hash; NMSettingSecretFlags private_key_flags; guint32 fwmark; + guint32 mtu; guint16 listen_port; bool private_key_valid:1; } NMSettingWireGuardPrivate; @@ -978,6 +980,22 @@ nm_setting_wireguard_get_listen_port (NMSettingWireGuard *self) return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->listen_port; } +/** + * nm_setting_wireguard_get_mtu: + * @self: the #NMSettingWireGuard instance + * + * Returns: the MTU of the setting. + * + * Since: 1.16 + */ +guint32 +nm_setting_wireguard_get_mtu (NMSettingWireGuard *self) +{ + g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), 0); + + return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->mtu; +} + /*****************************************************************************/ static void @@ -2160,18 +2178,21 @@ get_property (GObject *object, guint prop_id, NMSettingWireGuardPrivate *priv = NM_SETTING_WIREGUARD_GET_PRIVATE (setting); switch (prop_id) { + case PROP_FWMARK: + g_value_set_uint (value, priv->fwmark); + break; + case PROP_LISTEN_PORT: + g_value_set_uint (value, priv->listen_port); + break; + case PROP_MTU: + g_value_set_uint (value, priv->mtu); + break; case PROP_PRIVATE_KEY: g_value_set_string (value, priv->private_key); break; case PROP_PRIVATE_KEY_FLAGS: g_value_set_flags (value, priv->private_key_flags); break; - case PROP_LISTEN_PORT: - g_value_set_uint (value, priv->listen_port); - break; - case PROP_FWMARK: - g_value_set_uint (value, priv->fwmark); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2186,6 +2207,15 @@ set_property (GObject *object, guint prop_id, const char *str; switch (prop_id) { + case PROP_FWMARK: + priv->fwmark = g_value_get_uint (value); + break; + case PROP_LISTEN_PORT: + priv->listen_port = g_value_get_uint (value); + break; + case PROP_MTU: + priv->mtu = g_value_get_uint (value); + break; case PROP_PRIVATE_KEY: nm_clear_pointer (&priv->private_key, nm_free_secret); str = g_value_get_string (value); @@ -2203,12 +2233,6 @@ set_property (GObject *object, guint prop_id, case PROP_PRIVATE_KEY_FLAGS: priv->private_key_flags = g_value_get_flags (value); break; - case PROP_LISTEN_PORT: - priv->listen_port = g_value_get_uint (value); - break; - case PROP_FWMARK: - priv->fwmark = g_value_get_uint (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2338,6 +2362,25 @@ nm_setting_wireguard_class_init (NMSettingWireGuardClass *klass) | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + /** + * NMSettingWireGuard:mtu: + * + * If non-zero, only transmit packets of the specified size or smaller, + * breaking larger packets up into multiple fragments. + * + * If zero a default MTU is used. Note that contrary to wg-quick's MTU + * setting, this does not take into account the current routes at the + * time of activation. + * + * Since: 1.16 + **/ + obj_properties[PROP_MTU] = + g_param_spec_uint (NM_SETTING_WIREGUARD_MTU, "", "", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE + | NM_SETTING_PARAM_INFERRABLE + | G_PARAM_STATIC_STRINGS); + /* ---dbus--- * property: peers * format: array of 'a{sv}' diff --git a/libnm-core/nm-setting-wireguard.h b/libnm-core/nm-setting-wireguard.h index 3810aa3048..257439267c 100644 --- a/libnm-core/nm-setting-wireguard.h +++ b/libnm-core/nm-setting-wireguard.h @@ -126,19 +126,21 @@ int nm_wireguard_peer_cmp (const NMWireGuardPeer *a, #define NM_SETTING_WIREGUARD_SETTING_NAME "wireguard" +#define NM_SETTING_WIREGUARD_FWMARK "fwmark" +#define NM_SETTING_WIREGUARD_LISTEN_PORT "listen-port" #define NM_SETTING_WIREGUARD_PRIVATE_KEY "private-key" #define NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS "private-key-flags" -#define NM_SETTING_WIREGUARD_LISTEN_PORT "listen-port" -#define NM_SETTING_WIREGUARD_FWMARK "fwmark" #define NM_SETTING_WIREGUARD_PEERS "peers" -#define NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY "public-key" +#define NM_SETTING_WIREGUARD_MTU "mtu" + +#define NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS "allowed-ips" #define NM_WIREGUARD_PEER_ATTR_ENDPOINT "endpoint" +#define NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE "persistent-keepalive" #define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY "preshared-key" #define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS "preshared-key-flags" -#define NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS "allowed-ips" -#define NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE "persistent-keepalive" +#define NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY "public-key" /*****************************************************************************/ @@ -194,6 +196,9 @@ gboolean nm_setting_wireguard_remove_peer (NMSettingWireGuard *self, NM_AVAILABLE_IN_1_16 guint nm_setting_wireguard_clear_peers (NMSettingWireGuard *self); +NM_AVAILABLE_IN_1_16 +guint32 nm_setting_wireguard_get_mtu (NMSettingWireGuard *self); + /*****************************************************************************/ G_END_DECLS diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 136b0009de..cd523dae04 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1466,6 +1466,7 @@ global: nm_setting_wireguard_clear_peers; nm_setting_wireguard_get_fwmark; nm_setting_wireguard_get_listen_port; + nm_setting_wireguard_get_mtu; nm_setting_wireguard_get_peer; nm_setting_wireguard_get_peer_by_public_key; nm_setting_wireguard_get_peers_len; diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index b6577aed50..289342473a 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -827,6 +827,9 @@ ipv6.ip6-privacy=0 wifi.wake-on-wlan + + wireguard.mtu + diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c index d08d6ad7af..4e8d630e48 100644 --- a/src/devices/nm-device-wireguard.c +++ b/src/devices/nm-device-wireguard.c @@ -1247,6 +1247,34 @@ act_stage2_config (NMDevice *device, return NM_ACT_STAGE_RETURN_FAILURE; } +static guint32 +get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +{ + /* When "MTU" for `wg-quick up` is unset, it calls `ip route get` for + * each configured endpoint, to determine the suitable MTU how to reach + * each endpoint. + * For `wg-quick` this works very well, because whenever the script runs it + * determines the best setting at that point in time. It's simply not concerned + * with what happens later (and it's not around anyway). + * + * NetworkManager sticks around, so the right MTU would need to be re-determined + * whenever anything relevant changes. Which basically means, to re-evaluate whenever + * something related to addresses or routing changes (which happens all the time). + * + * The correct MTU indeed depends on the MTU setting of other interfaces (or routes). + * But it's still odd, that activating/deactivating a seemingly unrelated interface + * would trigger an MTU change. It's odd to explain/document and odd to implemented + * -- despite this being the reality. + * + * For now, only support configuring an explicit MTU, or leave the setting untouched. + * The same limitiation also applies to other "ip-tunnel" types, where we could use + * similar smarts for autodetecting the MTU. + */ + return nm_device_get_configured_mtu_from_connection (device, + NM_TYPE_SETTING_WIREGUARD, + out_source); +} + static void device_state_changed (NMDevice *device, NMDeviceState new_state, @@ -1275,8 +1303,17 @@ can_reapply_change (NMDevice *device, GError **error) { if (nm_streq (setting_name, NM_SETTING_WIREGUARD_SETTING_NAME)) { - /* we allow reapplying all WireGuard settings. */ - return TRUE; + /* Most, but not all WireGuard settings can be reapplied. Whitelist. + * + * MTU cannot be reapplied. */ + return nm_device_hash_check_invalid_keys (diffs, + NM_SETTING_WIREGUARD_SETTING_NAME, + error, + NM_SETTING_WIREGUARD_FWMARK, + NM_SETTING_WIREGUARD_LISTEN_PORT, + NM_SETTING_WIREGUARD_PEERS, + NM_SETTING_WIREGUARD_PRIVATE_KEY, + NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS); } return NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->can_reapply_change (device, @@ -1451,6 +1488,7 @@ nm_device_wireguard_class_init (NMDeviceWireGuardClass *klass) device_class->update_connection = update_connection; device_class->can_reapply_change = can_reapply_change; device_class->reapply_connection = reapply_connection; + device_class->get_configured_mtu = get_configured_mtu; obj_properties[PROP_PUBLIC_KEY] = g_param_spec_variant (NM_DEVICE_WIREGUARD_PUBLIC_KEY, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index cf4bb4d971..b24c9a7731 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -8871,6 +8871,10 @@ nm_device_get_configured_mtu_from_connection (NMDevice *self, if (setting) mtu = nm_setting_ip_tunnel_get_mtu (NM_SETTING_IP_TUNNEL (setting)); global_property_name = NM_CON_DEFAULT ("ip-tunnel.mtu"); + } else if (setting_type == NM_TYPE_SETTING_WIREGUARD) { + if (setting) + mtu = nm_setting_wireguard_get_mtu (NM_SETTING_WIREGUARD (setting)); + global_property_name = NM_CON_DEFAULT ("wireguard.mtu"); } else g_return_val_if_reached (0);