diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 87dde2c3af..5bc6c80038 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -6196,6 +6196,28 @@ _new_active_connection(NMManager *self, activation_reason, initial_state_flags, subject); + } else if (nm_connection_is_valid_secondary(sett_conn ? nm_settings_connection_get_connection(sett_conn) + : incompl_conn)) { + /** + * For non-plugin VPN connections, re-validate the corresponding device. + * Wireguard, for example, needs its own (virtual) device. + * If it, however, gets activated as secondary device, + * 'device' points to the primary device that is currently starting. + * Bringing up a WG tunnel this way will fail. + */ + NMDevice *_device = NULL; + gs_free_error GError *local = NULL; + _device = + nm_manager_get_best_device_for_connection(self, sett_conn, applied, TRUE, NULL, &local); + if (!_device) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "No suitable device found for non-plugin VPN connection (%s).", + local->message); + return NULL; + } + device = _device; } return (NMActiveConnection *) nm_act_request_new(sett_conn, diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index f7be1a9f87..be6e1c19bc 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -2163,11 +2163,10 @@ activate_secondary_connections(NMPolicy *self, NMConnection *connection, NMDevic break; } - if (!nm_connection_is_type(nm_settings_connection_get_connection(sett_conn), - NM_SETTING_VPN_SETTING_NAME)) { + if (!nm_connection_is_valid_secondary(nm_settings_connection_get_connection(sett_conn))) { _LOGW(LOGD_DEVICE, "secondary connection '%s (%s)' auto-activation failed: The connection is not a " - "VPN.", + "valid secondary.", nm_settings_connection_get_id(sett_conn), sec_uuid); success = FALSE; diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 64e2155d60..7d9735bb50 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -141,6 +141,7 @@ global: nm_connection_get_setting_vpn; nm_connection_get_setting_wimax; nm_connection_get_setting_wired; + nm_connection_get_setting_wireguard; nm_connection_get_setting_wireless; nm_connection_get_setting_wireless_security; nm_connection_get_type; @@ -2026,6 +2027,7 @@ libnm_1_50_4 { libnm_1_52_0 { global: + nm_connection_is_valid_secondary; nm_device_ipvlan_get_mode; nm_device_ipvlan_get_parent; nm_device_ipvlan_get_private; diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index 0fbadfb85c..81df36572e 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -15,6 +15,7 @@ #include "nm-connection-private.h" #include "nm-utils.h" #include "nm-setting-private.h" +#include "nm-setting-wireguard.h" #include "libnm-core-intern/nm-core-internal.h" /** @@ -2876,6 +2877,31 @@ nm_connection_is_type(NMConnection *connection, const char *type) return nm_streq0(type, nm_connection_get_connection_type(connection)); } +/** + * nm_connection_is_valid_secondary: + * @connection: the #NMConnection + * + * Checks whether the given connection can be activated as a secondary. + * + * Returns: %TRUE if the connection is a valid secondary. + * + * Since: 1.52 +*/ +gboolean +nm_connection_is_valid_secondary(NMConnection *connection) +{ + const char *type = nm_connection_get_connection_type(connection); + if (type) + return nm_streq(type, NM_SETTING_VPN_SETTING_NAME) + || nm_streq(type, NM_SETTING_WIREGUARD_SETTING_NAME); + + /* we have an incomplete (invalid) connection at hand. That can only + * happen during AddAndActivate. Determine whether it's VPN type based + * on the existence of a [vpn] section. */ + return !!nm_connection_get_setting_vpn(connection) + || nm_connection_get_setting_wireguard(connection); +} + int _nm_setting_sort_for_nm_assert(NMSetting *a, NMSetting *b) { @@ -3822,6 +3848,20 @@ nm_connection_get_setting_vpn(NMConnection *connection) return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_VPN); } +/** + * nm_connection_get_setting_wireguard: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingVpn the connection might contain. + * + * Returns: (transfer none): an #NMSettingVpn if the connection contains one, otherwise %NULL + **/ +NMSettingVpn * +nm_connection_get_setting_wireguard(NMConnection *connection) +{ + return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_WIREGUARD); +} + /** * nm_connection_get_setting_vxlan: * @connection: the #NMConnection diff --git a/src/libnm-core-public/nm-connection.h b/src/libnm-core-public/nm-connection.h index ff3e0f924a..3b8c60b3e6 100644 --- a/src/libnm-core-public/nm-connection.h +++ b/src/libnm-core-public/nm-connection.h @@ -240,12 +240,16 @@ NMSettingVpn *nm_connection_get_setting_vpn(NMConnection *connectio NMSettingWimax *nm_connection_get_setting_wimax(NMConnection *connection); NMSettingAdsl *nm_connection_get_setting_adsl(NMConnection *connection); NMSettingWired *nm_connection_get_setting_wired(NMConnection *connection); +NMSettingVpn *nm_connection_get_setting_wireguard(NMConnection *connection); NMSettingWireless *nm_connection_get_setting_wireless(NMConnection *connection); NMSettingWirelessSecurity *nm_connection_get_setting_wireless_security(NMConnection *connection); NMSettingVlan *nm_connection_get_setting_vlan(NMConnection *connection); NM_AVAILABLE_IN_1_2 NMSettingVxlan *nm_connection_get_setting_vxlan(NMConnection *connection); +NM_AVAILABLE_IN_1_52 +gboolean nm_connection_is_valid_secondary(NMConnection *connection); + G_END_DECLS #endif /* __NM_CONNECTION_H__ */ diff --git a/src/nmcli/settings.c b/src/nmcli/settings.c index 458b03e58d..bf497240bb 100644 --- a/src/nmcli/settings.c +++ b/src/nmcli/settings.c @@ -378,13 +378,13 @@ _set_fcn_precheck_connection_secondaries(NMClient *client, con = nmc_find_connection(connections, "uuid", *iter, NULL, FALSE); if (!con) { nmc_printerr(_("Warning: %s is not an UUID of any existing connection profile\n"), - *iter); - } else { + *iter); + } else { /* Currently, NM only supports VPN connections as secondaries */ - if (!nm_connection_is_type(con, NM_SETTING_VPN_SETTING_NAME)) { - g_set_error(error, 1, 0, _("'%s' is not a VPN connection profile"), *iter); + if (!nm_connection_is_valid_secondary(con)) { + g_set_error(error, 1, 0, _("'%s' is not a valid secondary profile"), *iter); return FALSE; - } + } } } else { con = nmc_find_connection(connections, "id", *iter, NULL, FALSE); @@ -392,10 +392,9 @@ _set_fcn_precheck_connection_secondaries(NMClient *client, g_set_error(error, 1, 0, _("'%s' is not a name of any existing profile"), *iter); return FALSE; } - - /* Currently, NM only supports VPN connections as secondaries */ - if (!nm_connection_is_type(con, NM_SETTING_VPN_SETTING_NAME)) { - g_set_error(error, 1, 0, _("'%s' is not a VPN connection profile"), *iter); + /* Currently, NM only supports VPN connections, including Wireguard, as secondaries */ + if (!nm_connection_is_valid_secondary(con)) { + g_set_error(error, 1, 0, _("'%s' is not a valid secondary profile"), *iter); return FALSE; }