diff options
author | Thomas Haller <thaller@redhat.com> | 2019-02-14 08:00:55 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-02-14 08:00:55 +0100 |
commit | c032690df227a609fc4b47c78269448576b6bda1 (patch) | |
tree | 35732416a81e7c3325e4e6c3a96243d7757e645e | |
parent | 2c881b8064e1cb5b227e5a3c61abfe95c6ddd05a (diff) | |
parent | a3d4dea61f2de02b075866db412c791320c4cbf8 (diff) | |
download | NetworkManager-c032690df227a609fc4b47c78269448576b6bda1.tar.gz |
all: merge branch 'th/various-for-wireguard-3'
https://github.com/NetworkManager/NetworkManager/pull/293
-rw-r--r-- | clients/cli/agent.c | 5 | ||||
-rw-r--r-- | clients/cli/common.c | 17 | ||||
-rw-r--r-- | clients/common/nm-secret-agent-simple.c | 256 | ||||
-rw-r--r-- | clients/common/nm-secret-agent-simple.h | 5 | ||||
-rw-r--r-- | libnm-core/nm-core-internal.h | 23 | ||||
-rw-r--r-- | libnm-core/nm-setting-vpn.c | 2 | ||||
-rw-r--r-- | libnm-core/nm-utils-private.h | 6 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 341 | ||||
-rw-r--r-- | libnm-core/nm-utils.h | 2 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 154 | ||||
-rw-r--r-- | shared/nm-utils/nm-macros-internal.h | 27 | ||||
-rw-r--r-- | shared/nm-utils/nm-secret-utils.h | 25 | ||||
-rw-r--r-- | src/devices/nm-device.c | 32 | ||||
-rw-r--r-- | src/devices/nm-device.h | 5 | ||||
-rw-r--r-- | src/nm-core-utils.h | 4 | ||||
-rw-r--r-- | src/nm-policy.c | 39 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 144 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 45 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 36 | ||||
-rw-r--r-- | src/platform/tests/test-link.c | 6 | ||||
-rw-r--r-- | src/vpn/nm-vpn-connection.h | 2 |
21 files changed, 946 insertions, 230 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c index a18eecc52d..6c116153ac 100644 --- a/clients/cli/agent.c +++ b/clients/cli/agent.c @@ -104,7 +104,10 @@ get_secrets_from_user (const NmcConfig *nmc_config, rl_startup_hook = set_deftext; pre_input_deftext = g_strdup (secret->value); } - pwd = nmc_readline (nmc_config, "%s (%s): ", secret->pretty_name, secret->entry_id); + if (secret->no_prompt_entry_id) + pwd = nmc_readline (nmc_config, "%s: ", secret->pretty_name); + else + pwd = nmc_readline (nmc_config, "%s (%s): ", secret->pretty_name, secret->entry_id); /* No password provided, cancel the secrets. */ if (!pwd) diff --git a/clients/cli/common.c b/clients/cli/common.c index b3342c1935..50dd0eb5cb 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -685,6 +685,8 @@ get_secrets_from_user (const NmcConfig *nmc_config, pwd = g_strdup (pwd); } else { if (ask) { + gboolean echo_on; + if (secret->value) { if (!g_strcmp0 (secret->vpn_type, NM_DBUS_INTERFACE ".openconnect")) { /* Do not present and ask user for openconnect secrets, we already have them */ @@ -697,11 +699,16 @@ get_secrets_from_user (const NmcConfig *nmc_config, } if (msg) g_print ("%s\n", msg); - pwd = nmc_readline_echo (nmc_config, - secret->is_secret - ? nmc_config->show_secrets - : TRUE, - "%s (%s): ", secret->pretty_name, secret->entry_id); + + echo_on = secret->is_secret + ? nmc_config->show_secrets + : TRUE; + + if (secret->no_prompt_entry_id) + pwd = nmc_readline_echo (nmc_config, echo_on, "%s: ", secret->pretty_name); + else + pwd = nmc_readline_echo (nmc_config, echo_on, "%s (%s): ", secret->pretty_name, secret->entry_id); + if (!pwd) pwd = g_strdup (""); } else { diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c index 1393793e4c..ffcb7c8978 100644 --- a/clients/common/nm-secret-agent-simple.c +++ b/clients/common/nm-secret-agent-simple.c @@ -38,6 +38,7 @@ #include "nm-vpn-service-plugin.h" #include "nm-vpn-helpers.h" +#include "nm-utils/nm-secret-utils.h" /*****************************************************************************/ @@ -47,6 +48,7 @@ typedef struct { NMSecretAgentSimple *self; NMConnection *connection; + const char *setting_name; char **hints; NMSecretAgentOldGetSecretsFunc callback; gpointer callback_data; @@ -145,7 +147,7 @@ _secret_real_free (NMSecretAgentSimpleSecret *secret) g_free ((char *) secret->pretty_name); g_free ((char *) secret->entry_id); - g_free (secret->value); + nm_free_secret (secret->value); g_free ((char *) secret->vpn_type); g_free (real->property); g_clear_object (&real->setting); @@ -154,46 +156,61 @@ _secret_real_free (NMSecretAgentSimpleSecret *secret) } static NMSecretAgentSimpleSecret * -_secret_real_new (NMSecretAgentSecretType secret_type, - const char *pretty_name, - NMSetting *setting, - const char *property, - const char *vpn_type) +_secret_real_new_plain (NMSecretAgentSecretType secret_type, + const char *pretty_name, + NMSetting *setting, + const char *property) { SecretReal *real; - const char *vpn_prefix; - const char *value; + gs_free char *value= NULL; nm_assert (property); nm_assert (NM_IS_SETTING (setting)); + nm_assert (NM_IN_SET (secret_type, NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, NM_SECRET_AGENT_SECRET_TYPE_SECRET)); + nm_assert (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property)); + nm_assert ((secret_type == NM_SECRET_AGENT_SECRET_TYPE_SECRET) == nm_setting_get_secret_flags (setting, property, NULL, NULL)); + + g_object_get (setting, property, &value, NULL); + + real = g_slice_new (SecretReal); + *real = (SecretReal) { + .base.secret_type = secret_type, + .base.pretty_name = g_strdup (pretty_name), + .base.entry_id = g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property), + .base.value = g_steal_pointer (&value), + .base.is_secret = (secret_type != NM_SECRET_AGENT_SECRET_TYPE_PROPERTY), + .setting = g_object_ref (setting), + .property = g_strdup (property), + }; + return &real->base; +} - real = g_slice_new0 (SecretReal); - *((NMSecretAgentSecretType *) &real->base.secret_type) = secret_type; - real->setting = g_object_ref (setting); - real->base.pretty_name = g_strdup (pretty_name); - real->property = g_strdup (property); - switch (secret_type) { - case NM_SECRET_AGENT_SECRET_TYPE_PROPERTY: - case NM_SECRET_AGENT_SECRET_TYPE_SECRET: - nm_assert (!vpn_type); - nm_assert (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property)); - nm_assert ((secret_type == NM_SECRET_AGENT_SECRET_TYPE_SECRET) == nm_setting_get_secret_flags (setting, property, NULL, NULL)); - real->base.entry_id = g_strdup_printf ("%s.%s", nm_setting_get_name (setting), property); - g_object_get (setting, property, &real->base.value, NULL); - real->base.is_secret = (secret_type != NM_SECRET_AGENT_SECRET_TYPE_PROPERTY); - break; - case NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET: - vpn_prefix = NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRETS; - value = nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), property); - real->base.entry_id = g_strdup_printf ("%s%s", vpn_prefix, property); - nm_assert (vpn_type); - real->base.vpn_type = g_strdup (vpn_type); - real->base.value = g_strdup (value); - real->base.is_secret = TRUE; - break; - } - nm_assert (real->base.entry_id); +static NMSecretAgentSimpleSecret * +_secret_real_new_vpn_secret (const char *pretty_name, + NMSetting *setting, + const char *property, + const char *vpn_type) +{ + SecretReal *real; + const char *value; + nm_assert (property); + nm_assert (NM_IS_SETTING_VPN (setting)); + nm_assert (vpn_type); + + value = nm_setting_vpn_get_secret (NM_SETTING_VPN (setting), property); + + real = g_slice_new (SecretReal); + *real = (SecretReal) { + .base.secret_type = NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET, + .base.pretty_name = g_strdup (pretty_name), + .base.entry_id = g_strdup_printf ("%s%s", NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRETS, property), + .base.value = g_strdup (value), + .base.is_secret = TRUE, + .base.vpn_type = g_strdup (vpn_type), + .setting = g_object_ref (setting), + .property = g_strdup (property), + }; return &real->base; } @@ -212,11 +229,10 @@ add_8021x_secrets (RequestData *request, char **iter; for (iter = request->hints; *iter; iter++) { - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _(*iter), - NM_SETTING (s_8021x), - *iter, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _(*iter), + NM_SETTING (s_8021x), + *iter); g_ptr_array_add (secrets, secret); } @@ -235,33 +251,29 @@ add_8021x_secrets (RequestData *request, * is not visible here since we only care about phase2 authentication * (and don't even care of which one) */ - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Username"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_IDENTITY, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Username"), + NM_SETTING (s_8021x), + NM_SETTING_802_1X_IDENTITY); g_ptr_array_add (secrets, secret); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_PASSWORD, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING (s_8021x), + NM_SETTING_802_1X_PASSWORD); g_ptr_array_add (secrets, secret); return TRUE; } if (nm_streq (eap_method, "tls")) { - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Identity"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_IDENTITY, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Identity"), + NM_SETTING (s_8021x), + NM_SETTING_802_1X_IDENTITY); g_ptr_array_add (secrets, secret); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Private key password"), - NM_SETTING (s_8021x), - NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Private key password"), + NM_SETTING (s_8021x), + NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); g_ptr_array_add (secrets, secret); return TRUE; } @@ -281,11 +293,10 @@ add_wireless_secrets (RequestData *request, return FALSE; if (NM_IN_STRSET (key_mgmt, "wpa-none", "wpa-psk", "sae")) { - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_wsec), - NM_SETTING_WIRELESS_SECURITY_PSK, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING (s_wsec), + NM_SETTING_WIRELESS_SECURITY_PSK); g_ptr_array_add (secrets, secret); return TRUE; } @@ -295,22 +306,20 @@ add_wireless_secrets (RequestData *request, char key[100]; index = nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Key"), - NM_SETTING (s_wsec), - nm_sprintf_buf (key, "wep-key%u", (guint) index), - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Key"), + NM_SETTING (s_wsec), + nm_sprintf_buf (key, "wep-key%u", (guint) index)); g_ptr_array_add (secrets, secret); return TRUE; } if (nm_streq (key_mgmt, "iee8021x")) { if (nm_streq0 (nm_setting_wireless_security_get_auth_alg (s_wsec), "leap")) { - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_wsec), - NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING (s_wsec), + NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD); g_ptr_array_add (secrets, secret); return TRUE; } else @@ -330,23 +339,20 @@ add_pppoe_secrets (RequestData *request, NMSettingPppoe *s_pppoe = nm_connection_get_setting_pppoe (request->connection); NMSecretAgentSimpleSecret *secret; - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Username"), - NM_SETTING (s_pppoe), - NM_SETTING_PPPOE_USERNAME, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Username"), + NM_SETTING (s_pppoe), + NM_SETTING_PPPOE_USERNAME); g_ptr_array_add (secrets, secret); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("Service"), - NM_SETTING (s_pppoe), - NM_SETTING_PPPOE_SERVICE, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("Service"), + NM_SETTING (s_pppoe), + NM_SETTING_PPPOE_SERVICE); g_ptr_array_add (secrets, secret); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_pppoe), - NM_SETTING_PPPOE_PASSWORD, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING (s_pppoe), + NM_SETTING_PPPOE_PASSWORD); g_ptr_array_add (secrets, secret); return TRUE; } @@ -374,11 +380,10 @@ add_vpn_secret_helper (GPtrArray *secrets, NMSettingVpn *s_vpn, const char *name flags = get_vpn_secret_flags (s_vpn, name); if ( flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED || flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) { - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET, - ui_name, - NM_SETTING (s_vpn), - name, - nm_setting_vpn_get_service_type (s_vpn)); + secret = _secret_real_new_vpn_secret (ui_name, + NM_SETTING (s_vpn), + name, + nm_setting_vpn_get_service_type (s_vpn)); /* Check for duplicates */ for (i = 0; i < secrets->len; i++) { @@ -506,11 +511,10 @@ _auth_dialog_exited (GPid pid, int status, gpointer user_data) if (!g_key_file_get_boolean (keyfile, groups[i], "ShouldAsk", NULL)) continue; - g_ptr_array_add (secrets, _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_VPN_SECRET, - g_key_file_get_string (keyfile, groups[i], "Label", NULL), - NM_SETTING (s_vpn), - groups[i], - nm_setting_vpn_get_service_type (s_vpn))); + g_ptr_array_add (secrets, _secret_real_new_vpn_secret (g_key_file_get_string (keyfile, groups[i], "Label", NULL), + NM_SETTING (s_vpn), + groups[i], + nm_setting_vpn_get_service_type (s_vpn))); } out: @@ -782,22 +786,20 @@ request_secrets_from_ui (RequestData *request) title = _("PIN code required"); msg = g_strdup (_("PIN code is needed for the mobile broadband device")); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, - _("PIN"), - NM_SETTING (s_gsm), - NM_SETTING_GSM_PIN, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_PROPERTY, + _("PIN"), + NM_SETTING (s_gsm), + NM_SETTING_GSM_PIN); g_ptr_array_add (secrets, secret); } else { title = _("Mobile broadband network password"); msg = g_strdup_printf (_("A password is required to connect to '%s'."), nm_connection_get_id (request->connection)); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_gsm), - NM_SETTING_GSM_PASSWORD, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING (s_gsm), + NM_SETTING_GSM_PASSWORD); g_ptr_array_add (secrets, secret); } } else if (nm_connection_is_type (request->connection, NM_SETTING_MACSEC_SETTING_NAME)) { @@ -808,11 +810,10 @@ request_secrets_from_ui (RequestData *request) if (nm_setting_macsec_get_mode (s_macsec) == NM_SETTING_MACSEC_MODE_PSK) { title = _("MACsec PSK authentication"); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("MKA CAK"), - NM_SETTING (s_macsec), - NM_SETTING_MACSEC_MKA_CAK, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("MKA CAK"), + NM_SETTING (s_macsec), + NM_SETTING_MACSEC_MKA_CAK); g_ptr_array_add (secrets, secret); } else { title = _("MACsec EAP authentication"); @@ -826,11 +827,10 @@ request_secrets_from_ui (RequestData *request) msg = g_strdup_printf (_("A password is required to connect to '%s'."), nm_connection_get_id (request->connection)); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - NM_SETTING (s_cdma), - NM_SETTING_CDMA_PASSWORD, - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + NM_SETTING (s_cdma), + NM_SETTING_CDMA_PASSWORD); g_ptr_array_add (secrets, secret); } else if (nm_connection_is_type (request->connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { NMSetting *setting = NULL; @@ -850,11 +850,10 @@ request_secrets_from_ui (RequestData *request) msg = g_strdup_printf (_("A password is required to connect to '%s'."), nm_connection_get_id (request->connection)); - secret = _secret_real_new (NM_SECRET_AGENT_SECRET_TYPE_SECRET, - _("Password"), - setting, - "password", - NULL); + secret = _secret_real_new_plain (NM_SECRET_AGENT_SECRET_TYPE_SECRET, + _("Password"), + setting, + "password"); g_ptr_array_add (secrets, secret); } else if (nm_connection_is_type (request->connection, NM_SETTING_VPN_SETTING_NAME)) { title = _("VPN password required"); @@ -873,6 +872,9 @@ request_secrets_from_ui (RequestData *request) } else goto out_fail; + if (secrets->len == 0) + goto out_fail; + g_signal_emit (request->self, signals[REQUEST_SECRETS], 0, request->request_id, title, msg, secrets); return; @@ -902,6 +904,7 @@ get_secrets (NMSecretAgentOld *agent, RequestData *request; gs_free_error GError *error = NULL; gs_free char *request_id = NULL; + const char *request_id_setting_name; request_id = g_strdup_printf ("%s/%s", connection_path, setting_name); @@ -921,10 +924,15 @@ get_secrets (NMSecretAgentOld *agent, return; } + nm_assert (g_str_has_suffix (request_id, setting_name)); + request_id_setting_name = &request_id[strlen (request_id) - strlen (setting_name)]; + nm_assert (nm_streq (request_id_setting_name, setting_name)); + request = g_slice_new (RequestData); *request = (RequestData) { .self = self, .connection = g_object_ref (connection), + .setting_name = request_id_setting_name, .hints = g_strdupv ((char **) hints), .callback = callback, .callback_data = callback_data, diff --git a/clients/common/nm-secret-agent-simple.h b/clients/common/nm-secret-agent-simple.h index 8cae17a8c2..3e61dace4c 100644 --- a/clients/common/nm-secret-agent-simple.h +++ b/clients/common/nm-secret-agent-simple.h @@ -28,12 +28,13 @@ typedef enum { } NMSecretAgentSecretType; typedef struct { - const NMSecretAgentSecretType secret_type; + NMSecretAgentSecretType secret_type; const char *pretty_name; const char *entry_id; char *value; const char *vpn_type; - gboolean is_secret; + bool is_secret:1; + bool no_prompt_entry_id:1; } NMSecretAgentSimpleSecret; #define NM_SECRET_AGENT_ENTRY_ID_PREFX_VPN_SECRETS "vpn.secrets." diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 2d66eb83fb..19a914956e 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -129,7 +129,7 @@ /*****************************************************************************/ -#define NM_SETTING_SECRET_FLAGS_ALL \ +#define NM_SETTING_SECRET_FLAG_ALL \ ((NMSettingSecretFlags) ( NM_SETTING_SECRET_FLAG_NONE \ | NM_SETTING_SECRET_FLAG_AGENT_OWNED \ | NM_SETTING_SECRET_FLAG_NOT_SAVED \ @@ -138,7 +138,7 @@ static inline gboolean _nm_setting_secret_flags_valid (NMSettingSecretFlags flags) { - return !NM_FLAGS_ANY (flags, ~NM_SETTING_SECRET_FLAGS_ALL); + return !NM_FLAGS_ANY (flags, ~NM_SETTING_SECRET_FLAG_ALL); } /*****************************************************************************/ @@ -614,6 +614,25 @@ gboolean _nm_setting_sriov_sort_vfs (NMSettingSriov *setting); /*****************************************************************************/ +typedef struct _NMSockAddrEndpoint NMSockAddrEndpoint; + +NMSockAddrEndpoint *nm_sock_addr_endpoint_new (const char *endpoint); + +NMSockAddrEndpoint *nm_sock_addr_endpoint_ref (NMSockAddrEndpoint *self); +void nm_sock_addr_endpoint_unref (NMSockAddrEndpoint *self); + +const char *nm_sock_addr_endpoint_get_endpoint (NMSockAddrEndpoint *self); +const char *nm_sock_addr_endpoint_get_host (NMSockAddrEndpoint *self); +gint32 nm_sock_addr_endpoint_get_port (NMSockAddrEndpoint *self); + +gboolean nm_sock_addr_endpoint_get_fixed_sockaddr (NMSockAddrEndpoint *self, + gpointer sockaddr); + +#define nm_auto_unref_sockaddrendpoint nm_auto(_nm_auto_unref_sockaddrendpoint) +NM_AUTO_DEFINE_FCN_VOID0 (NMSockAddrEndpoint *, _nm_auto_unref_sockaddrendpoint, nm_sock_addr_endpoint_unref) + +/*****************************************************************************/ + typedef struct _NMSettInfoSetting NMSettInfoSetting; typedef struct _NMSettInfoProperty NMSettInfoProperty; diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c index e9501ab1f7..a9a9c0df41 100644 --- a/libnm-core/nm-setting-vpn.c +++ b/libnm-core/nm-setting-vpn.c @@ -763,7 +763,7 @@ get_secret_flags (NMSetting *setting, return TRUE; } - i64 = _nm_utils_ascii_str_to_int64 (flags_val, 10, 0, NM_SETTING_SECRET_FLAGS_ALL, -1); + i64 = _nm_utils_ascii_str_to_int64 (flags_val, 10, 0, NM_SETTING_SECRET_FLAG_ALL, -1); if ( i64 == -1 || !_nm_setting_secret_flags_valid (i64)) { /* The flags keys is set to an unexpected value. That is a configuration diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index b61260cb22..46af26ed02 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -41,6 +41,12 @@ struct _NMVariantAttributeSpec { gboolean _nm_utils_string_slist_validate (GSList *list, const char **valid_values); +gboolean _nm_utils_secret_flags_validate (NMSettingSecretFlags secret_flags, + const char *setting_name, + const char *property_name, + NMSettingSecretFlags disallowed_flags, + GError **error); + gboolean _nm_utils_wps_method_validate (NMSettingWirelessSecurityWpsMethod wps_method, const char *setting_name, const char *property_name, diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 506f434497..c5855da196 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -59,6 +59,277 @@ * access points and devices, among other things. */ +/*****************************************************************************/ + +struct _NMSockAddrEndpoint { + const char *host; + guint16 port; + guint refcount; + char endpoint[]; +}; + +static gboolean +NM_IS_SOCK_ADDR_ENDPOINT (const NMSockAddrEndpoint *self) +{ + return self && self->refcount > 0; +} + +static const char * +_parse_endpoint (char *str, + guint16 *out_port) +{ + char *s; + const char *s_port; + gint16 port; + + /* Like + * - https://git.zx2c4.com/WireGuard/tree/src/tools/config.c?id=5e99a6d43fe2351adf36c786f5ea2086a8fe7ab8#n192 + * - https://github.com/systemd/systemd/blob/911649fdd43f3a9158b847947724a772a5a45c34/src/network/netdev/wireguard.c#L614 + */ + + g_strstrip (str); + + if (!str[0]) + return NULL; + + if (str[0] == '[') { + str++; + s = strchr (str, ']'); + if (!s) + return NULL; + if (s == str) + return NULL; + if (s[1] != ':') + return NULL; + if (!s[2]) + return NULL; + *s = '\0'; + s_port = &s[2]; + } else { + s = strrchr (str, ':'); + if (!s) + return NULL; + if (s == str) + return NULL; + if (!s[1]) + return NULL; + *s = '\0'; + s_port = &s[1]; + } + + if (!NM_STRCHAR_ALL (s_port, ch, (ch >= '0' && ch <= '9'))) + return NULL; + + port = _nm_utils_ascii_str_to_int64 (s_port, 10, 1, G_MAXUINT16, 0); + if (port == 0) + return NULL; + + *out_port = port; + return str; +} + +/** + * nm_sock_addr_endpoint_new: + * @endpoint: the endpoint string. + * + * This function cannot fail, even if the @endpoint is invalid. + * The reason is to allow NMSockAddrEndpoint also to be used + * for tracking invalid endpoints. Use nm_sock_addr_endpoint_get_host() + * to determine whether the endpoint is valid. + * + * Returns: (transfer full): the new #NMSockAddrEndpoint endpoint. + */ +NMSockAddrEndpoint * +nm_sock_addr_endpoint_new (const char *endpoint) +{ + NMSockAddrEndpoint *ep; + gsize l_endpoint; + gsize l_host = 0; + gsize i; + gs_free char *host_clone = NULL; + const char *host; + guint16 port; + + g_return_val_if_fail (endpoint, NULL); + + l_endpoint = strlen (endpoint) + 1; + + host = _parse_endpoint (nm_strndup_a (200, endpoint, l_endpoint - 1, &host_clone), + &port); + + if (host) + l_host = strlen (host) + 1; + + ep = g_malloc (sizeof (NMSockAddrEndpoint) + l_endpoint + l_host); + ep->refcount = 1; + memcpy (ep->endpoint, endpoint, l_endpoint); + if (host) { + i = l_endpoint; + memcpy (&ep->endpoint[i], host, l_host); + ep->host = &ep->endpoint[i]; + ep->port = port; + } else { + ep->host = NULL; + ep->port = 0; + } + return ep; +} + +/** + * nm_sock_addr_endpoint_ref: + * @self: (allow-none): the #NMSockAddrEndpoint + */ +NMSockAddrEndpoint * +nm_sock_addr_endpoint_ref (NMSockAddrEndpoint *self) +{ + if (!self) + return NULL; + + g_return_val_if_fail (NM_IS_SOCK_ADDR_ENDPOINT (self), NULL); + + nm_assert (self->refcount < G_MAXUINT); + + self->refcount++; + return self; +} + +/** + * nm_sock_addr_endpoint_unref: + * @self: (allow-none): the #NMSockAddrEndpoint + */ +void +nm_sock_addr_endpoint_unref (NMSockAddrEndpoint *self) +{ + if (!self) + return; + + g_return_if_fail (NM_IS_SOCK_ADDR_ENDPOINT (self)); + + if (--self->refcount == 0) + g_free (self); +} + +/** + * nm_sock_addr_endpoint_get_endpoint: + * @self: the #NMSockAddrEndpoint + * + * Gives the endpoint string. Since #NMSockAddrEndpoint's only + * information is the endpoint string, this can be used for comparing + * to instances for equality and order them lexically. + * + * Returns: (transfer none): the endpoint. + */ +const char * +nm_sock_addr_endpoint_get_endpoint (NMSockAddrEndpoint *self) +{ + g_return_val_if_fail (NM_IS_SOCK_ADDR_ENDPOINT (self), NULL); + + return self->endpoint; +} + +/** + * nm_sock_addr_endpoint_get_host: + * @self: the #NMSockAddrEndpoint + * + * Returns: (transfer none): the parsed host part of the endpoint. + * If the endpoint is invalid, %NULL will be returned. + */ +const char * +nm_sock_addr_endpoint_get_host (NMSockAddrEndpoint *self) +{ + g_return_val_if_fail (NM_IS_SOCK_ADDR_ENDPOINT (self), NULL); + + return self->host; +} + +/** + * nm_sock_addr_endpoint_get_port: + * @self: the #NMSockAddrEndpoint + * + * Returns: the parsed port part of the endpoint (the service). + * If the endpoint is invalid, -1 will be returned. + */ +gint32 +nm_sock_addr_endpoint_get_port (NMSockAddrEndpoint *self) +{ + g_return_val_if_fail (NM_IS_SOCK_ADDR_ENDPOINT (self), -1); + + return self->host ? (int) self->port : -1; +} + +gboolean +nm_sock_addr_endpoint_get_fixed_sockaddr (NMSockAddrEndpoint *self, + gpointer sockaddr) +{ + int addr_family; + NMIPAddr addrbin; + const char *s; + guint scope_id = 0; + + g_return_val_if_fail (NM_IS_SOCK_ADDR_ENDPOINT (self), FALSE); + g_return_val_if_fail (sockaddr, FALSE); + + if (!self->host) + return FALSE; + + if (nm_utils_parse_inaddr_bin (AF_UNSPEC, self->host, &addr_family, &addrbin)) + goto good; + + /* See if there is an IPv6 scope-id... + * + * Note that it does not make sense to persist connection profiles to disk, + * that refenrence a scope-id (because the interface's ifindex changes on + * reboot). However, we also support runtime only changes like `nmcli device modify` + * where nothing is persisted to disk. At least in that case, passing a scope-id + * might be reasonable. So, parse that too. */ + s = strchr (self->host, '%'); + if (!s) + return FALSE; + + if ( s[1] == '\0' + || !NM_STRCHAR_ALL (&s[1], ch, (ch >= '0' && ch <= '9'))) + return FALSE; + + scope_id = _nm_utils_ascii_str_to_int64 (&s[1], 10, 0, G_MAXINT32, G_MAXUINT); + if (scope_id == G_MAXUINT && errno) + return FALSE; + + { + gs_free char *tmp_str = NULL; + const char *host_part; + + host_part = nm_strndup_a (200, self->host, s - self->host, &tmp_str); + if (nm_utils_parse_inaddr_bin (AF_INET6, host_part, &addr_family, &addrbin)) + goto good; + } + + return FALSE; + +good: + switch (addr_family) { + case AF_INET: + *((struct sockaddr_in *) sockaddr) = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_addr = addrbin.addr4_struct, + .sin_port = htons (self->port), + }; + return TRUE; + case AF_INET6: + *((struct sockaddr_in6 *) sockaddr) = (struct sockaddr_in6) { + .sin6_family = AF_INET6, + .sin6_addr = addrbin.addr6, + .sin6_port = htons (self->port), + .sin6_scope_id = scope_id, + .sin6_flowinfo = 0, + }; + return TRUE; + } + + return FALSE; +} + +/*****************************************************************************/ + struct IsoLangToEncodings { const char *lang; @@ -4309,6 +4580,62 @@ _nm_utils_hwaddr_from_dbus (GVariant *dbus_value, /*****************************************************************************/ +/* Validate secret-flags. Most settings don't validate them, which is a bug. + * But we possibly cannot enforce a strict validation now. + * + * For new settings, they shall validate the secret-flags strictly. */ +gboolean +_nm_utils_secret_flags_validate (NMSettingSecretFlags secret_flags, + const char *setting_name, + const char *property_name, + NMSettingSecretFlags disallowed_flags, + GError **error) +{ + if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) + return TRUE; + + if (NM_FLAGS_ANY (secret_flags, ~NM_SETTING_SECRET_FLAG_ALL)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("unknown secret flags")); + if (setting_name) + g_prefix_error (error, "%s.%s: ", setting_name, property_name); + return FALSE; + } + + if (!nm_utils_is_power_of_two (secret_flags)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("conflicting secret flags")); + if (setting_name) + g_prefix_error (error, "%s.%s: ", setting_name, property_name); + return FALSE; + } + + if (NM_FLAGS_ANY (secret_flags, disallowed_flags)) { + if (NM_FLAGS_HAS (secret_flags, NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("secret flags must not be \"not-required\"")); + if (setting_name) + g_prefix_error (error, "%s.%s: ", setting_name, property_name); + return FALSE; + } + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("unsupported secret flags")); + if (setting_name) + g_prefix_error (error, "%s.%s: ", setting_name, property_name); + return FALSE; + } + + return TRUE; +} + gboolean _nm_utils_wps_method_validate (NMSettingWirelessSecurityWpsMethod wps_method, const char *setting_name, @@ -6020,15 +6347,15 @@ _nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers) name = nm_team_link_watcher_get_name (watcher); g_variant_builder_add (&watcher_builder, "{sv}", - "name", - g_variant_new_string (name)); + "name", + g_variant_new_string (name)); - if nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL) { + if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { int_val = nm_team_link_watcher_get_delay_up (watcher); if (int_val) { g_variant_builder_add (&watcher_builder, "{sv}", - "delay-up", - g_variant_new_int32 (int_val)); + "delay-up", + g_variant_new_int32 (int_val)); } int_val = nm_team_link_watcher_get_delay_down (watcher); if (int_val) { @@ -6063,7 +6390,7 @@ _nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers) "target-host", g_variant_new_string (nm_team_link_watcher_get_target_host (watcher))); - if nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING) { + if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING)) { g_variant_builder_add (&builder, "a{sv}", &watcher_builder); continue; } @@ -6155,7 +6482,7 @@ _nm_utils_team_link_watchers_from_variant (GVariant *value) val2 = 0; if (!g_variant_lookup (watcher_var, "missed-max", "i", &val3)) val3 = 3; - if nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING) { + if (nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING)) { if (!g_variant_lookup (watcher_var, "vlanid", "i", &val4)) val4 = -1; if (!g_variant_lookup (watcher_var, "source-host", "&s", &source_host)) diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index cf9572b907..34aae560e3 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -40,6 +40,8 @@ G_BEGIN_DECLS +/*****************************************************************************/ + typedef struct _NMVariantAttributeSpec NMVariantAttributeSpec; /* SSID helpers */ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 96eafa3a68..7d97296ab4 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -5522,6 +5522,158 @@ test_setting_user_data (void) /*****************************************************************************/ +typedef union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +} SockAddrUnion; + +static void +_sock_addr_endpoint (const char *endpoint, + const char *host, + gint32 port) +{ + nm_auto_unref_sockaddrendpoint NMSockAddrEndpoint *ep = NULL; + const char *s_endpoint; + const char *s_host; + gint32 s_port; + SockAddrUnion sockaddr = { }; + + g_assert (endpoint); + g_assert (!host == (port == -1)); + g_assert (port >= -1 && port <= G_MAXUINT16); + + ep = nm_sock_addr_endpoint_new (endpoint); + g_assert (ep); + + s_endpoint = nm_sock_addr_endpoint_get_endpoint (ep); + s_host = nm_sock_addr_endpoint_get_host (ep); + s_port = nm_sock_addr_endpoint_get_port (ep); + g_assert_cmpstr (endpoint, ==, s_endpoint); + g_assert_cmpstr (host, ==, s_host); + g_assert_cmpint (port, ==, s_port); + + g_assert (!nm_sock_addr_endpoint_get_fixed_sockaddr (ep, &sockaddr)); + + if (endpoint[0] != ' ') { + gs_free char *endpoint2 = NULL; + + /* also test with a leading space */ + endpoint2 = g_strdup_printf (" %s", endpoint); + _sock_addr_endpoint (endpoint2, host, port); + } + + if (endpoint[0] && endpoint[strlen (endpoint) - 1] != ' ') { + gs_free char *endpoint2 = NULL; + + /* also test with a trailing space */ + endpoint2 = g_strdup_printf ("%s ", endpoint); + _sock_addr_endpoint (endpoint2, host, port); + } +} + +static void +_sock_addr_endpoint_fixed (const char *endpoint, + const char *host, + guint16 port, + guint scope_id) +{ + nm_auto_unref_sockaddrendpoint NMSockAddrEndpoint *ep = NULL; + const char *s_endpoint; + const char *s_host; + gint32 s_port; + int addr_family; + NMIPAddr addrbin; + SockAddrUnion sockaddr = { }; + + g_assert (endpoint); + g_assert (host); + g_assert (port > 0); + + if (!nm_utils_parse_inaddr_bin (AF_UNSPEC, host, &addr_family, &addrbin)) + g_assert_not_reached (); + + ep = nm_sock_addr_endpoint_new (endpoint); + g_assert (ep); + + s_endpoint = nm_sock_addr_endpoint_get_endpoint (ep); + s_host = nm_sock_addr_endpoint_get_host (ep); + s_port = nm_sock_addr_endpoint_get_port (ep); + g_assert_cmpstr (endpoint, ==, s_endpoint); + g_assert_cmpstr (NULL, !=, s_host); + g_assert_cmpint (port, ==, s_port); + + if (!nm_sock_addr_endpoint_get_fixed_sockaddr (ep, &sockaddr)) + g_assert_not_reached (); + + g_assert_cmpint (sockaddr.sa.sa_family, ==, addr_family); + if (addr_family == AF_INET) { + const SockAddrUnion s = { + .in = { + .sin_family = AF_INET, + .sin_addr = addrbin.addr4_struct, + .sin_port = htons (port), + }, + }; + + g_assert_cmpint (sockaddr.in.sin_addr.s_addr, ==, addrbin.addr4); + g_assert_cmpint (sockaddr.in.sin_port, ==, htons (port)); + g_assert (memcmp (&s, &sockaddr, sizeof (s.in)) == 0); + } else if (addr_family == AF_INET6) { + const SockAddrUnion s = { + .in6 = { + .sin6_family = AF_INET6, + .sin6_addr = addrbin.addr6, + .sin6_scope_id = scope_id, + .sin6_port = htons (port), + }, + }; + + g_assert (memcmp (&sockaddr.in6.sin6_addr, &addrbin, sizeof (addrbin.addr6)) == 0); + g_assert_cmpint (sockaddr.in6.sin6_port, ==, htons (port)); + g_assert_cmpint (sockaddr.in6.sin6_scope_id, ==, scope_id); + g_assert_cmpint (sockaddr.in6.sin6_flowinfo, ==, 0); + g_assert (memcmp (&s, &sockaddr, sizeof (s.in6)) == 0); + } else + g_assert_not_reached (); +} + +static void +test_sock_addr_endpoint (void) +{ + _sock_addr_endpoint ("", NULL, -1); + _sock_addr_endpoint (":", NULL, -1); + _sock_addr_endpoint ("a", NULL, -1); + _sock_addr_endpoint ("a:", NULL, -1); + _sock_addr_endpoint (":a", NULL, -1); + _sock_addr_endpoint ("[]:a", NULL, -1); + _sock_addr_endpoint ("[]a", NULL, -1); + _sock_addr_endpoint ("[]:", NULL, -1); + _sock_addr_endpoint ("[a]b", NULL, -1); + _sock_addr_endpoint ("[a:b", NULL, -1); + _sock_addr_endpoint ("[a[:b", NULL, -1); + _sock_addr_endpoint ("a:6", "a", 6); + _sock_addr_endpoint ("a:6", "a", 6); + _sock_addr_endpoint ("[a]:6", "a", 6); + _sock_addr_endpoint ("[a]:6", "a", 6); + _sock_addr_endpoint ("[a]:655", "a", 655); + _sock_addr_endpoint ("[ab]:][6", NULL, -1); + _sock_addr_endpoint ("[ab]:]:[6", NULL, -1); + _sock_addr_endpoint ("[a[]:b", NULL, -1); + _sock_addr_endpoint ("[192.169.6.x]:6", "192.169.6.x", 6); + _sock_addr_endpoint ("[192.169.6.x]:0", NULL, -1); + _sock_addr_endpoint ("192.169.6.7:0", NULL, -1); + + _sock_addr_endpoint_fixed ("192.169.6.7:6", "192.169.6.7", 6, 0); + _sock_addr_endpoint_fixed ("[192.169.6.7]:6", "192.169.6.7", 6, 0); + _sock_addr_endpoint_fixed ("[a:b::]:6", "a:b::", 6, 0); + _sock_addr_endpoint_fixed ("[a:b::%7]:6", "a:b::", 6, 7); + _sock_addr_endpoint_fixed ("a:b::1%75:6", "a:b::1", 6, 75); + _sock_addr_endpoint_fixed ("a:b::1%0:64", "a:b::1", 64, 0); +} + +/*****************************************************************************/ + static void test_hexstr2bin (void) { @@ -7735,6 +7887,8 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_setting_compare_default_strv", test_setting_compare_default_strv); g_test_add_func ("/core/general/test_setting_user_data", test_setting_user_data); + g_test_add_func ("/core/general/test_sock_addr_endpoint", test_sock_addr_endpoint); + g_test_add_func ("/core/general/hexstr2bin", test_hexstr2bin); g_test_add_func ("/core/general/nm_strquote", test_nm_strquote); g_test_add_func ("/core/general/test_nm_utils_uuid_generate_from_string", test_nm_utils_uuid_generate_from_string); diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 55cdd374da..42299c9635 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -449,7 +449,7 @@ NM_G_ERROR_MSG (GError *error) /*****************************************************************************/ /* macro to return strlen() of a compile time string. */ -#define NM_STRLEN(str) ( sizeof ("" str) - 1 ) +#define NM_STRLEN(str) ( sizeof (""str"") - 1 ) /* returns the length of a NULL terminated array of pointers, * like g_strv_length() does. The difference is: @@ -860,12 +860,33 @@ fcn (void) \ /*****************************************************************************/ -#define nm_streq(s1, s2) (strcmp (s1, s2) == 0) -#define nm_streq0(s1, s2) (g_strcmp0 (s1, s2) == 0) +static inline gboolean +nm_streq (const char *s1, const char *s2) +{ + return strcmp (s1, s2) == 0; +} + +static inline gboolean +nm_streq0 (const char *s1, const char *s2) +{ + return (s1 == s2) + || (s1 && s2 && strcmp (s1, s2) == 0); +} #define NM_STR_HAS_PREFIX(str, prefix) \ (strncmp ((str), ""prefix"", NM_STRLEN (prefix)) == 0) +#define NM_STR_HAS_SUFFIX(str, suffix) \ + ({ \ + const char *_str = (str); \ + gsize _l = strlen (_str); \ + \ + ( (_l >= NM_STRLEN (suffix)) \ + && (memcmp (&_str[_l - NM_STRLEN (suffix)], \ + ""suffix"", \ + NM_STRLEN (suffix)) == 0)); \ + }) + /*****************************************************************************/ static inline GString * diff --git a/shared/nm-utils/nm-secret-utils.h b/shared/nm-utils/nm-secret-utils.h index 9df31afea1..1bd518704e 100644 --- a/shared/nm-utils/nm-secret-utils.h +++ b/shared/nm-utils/nm-secret-utils.h @@ -76,6 +76,19 @@ typedef struct { } NMSecretPtr; static inline void +nm_secret_ptr_bzero (NMSecretPtr *secret) +{ + if (secret) { + if (secret->len > 0) { + if (secret->ptr) + nm_explicit_bzero (secret->ptr, secret->len); + } + } +} + +#define nm_auto_bzero_secret_ptr nm_auto(nm_secret_ptr_bzero) + +static inline void nm_secret_ptr_clear (NMSecretPtr *secret) { if (secret) { @@ -90,12 +103,24 @@ nm_secret_ptr_clear (NMSecretPtr *secret) #define nm_auto_clear_secret_ptr nm_auto(nm_secret_ptr_clear) +#define NM_SECRET_PTR_INIT() \ + ((const NMSecretPtr) { \ + .len = 0, \ + .ptr = NULL, \ + }) + #define NM_SECRET_PTR_STATIC(_len) \ ((const NMSecretPtr) { \ .len = _len, \ .ptr = ((guint8 [_len]) { }), \ }) +#define NM_SECRET_PTR_ARRAY(_arr) \ + ((const NMSecretPtr) { \ + .len = G_N_ELEMENTS (_arr) * sizeof ((_arr)[0]), \ + .ptr = &((_arr)[0]), \ + }) + static inline void nm_secret_ptr_clear_static (const NMSecretPtr *secret) { diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 8b68469cd9..2d4ae32cd9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2042,9 +2042,14 @@ nm_device_get_route_metric_default (NMDeviceType device_type) */ switch (device_type) { - /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT) */ + + /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). + * + * Note that returning 50 from this function means that this device-type is + * in some aspects a VPN. */ case NM_DEVICE_TYPE_WIREGUARD: - return 50; + return NM_VPN_ROUTE_METRIC_DEFAULT; + case NM_DEVICE_TYPE_ETHERNET: case NM_DEVICE_TYPE_VETH: return 100; @@ -6481,23 +6486,25 @@ static void activate_stage2_device_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceClass *klass; NMActStageReturn ret; gboolean no_firmware = FALSE; CList *iter; nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); - /* Assumed connections were already set up outside NetworkManager */ - if (!nm_device_sys_iface_state_is_external_or_assume (self)) { - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - + if (!nm_device_sys_iface_state_is_external_or_assume (self)) _ethtool_state_set (self); + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { if (!tc_commit (self)) { _LOGW (LOGD_IP6, "failed applying traffic control rules"); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return; } + } + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { if (!nm_device_bring_up (self, FALSE, &no_firmware)) { if (no_firmware) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING); @@ -6505,15 +6512,21 @@ activate_stage2_device_config (NMDevice *self) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return; } + } - ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &failure_reason); + klass = NM_DEVICE_GET_CLASS (self); + if ( klass->act_stage2_config_also_for_external_or_assume + || !nm_device_sys_iface_state_is_external_or_assume (self)) { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + + ret = klass->act_stage2_config (self, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) return; - else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) { + nm_assert (ret == NM_ACT_STAGE_RETURN_FAILURE); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); return; } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); } /* If we have slaves that aren't yet enslaved, do that now */ @@ -6530,6 +6543,7 @@ activate_stage2_device_config (NMDevice *self) } lldp_init (self, TRUE); + nm_device_activate_schedule_stage3_ip_config_start (self); } diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index b684e2f943..303b92325b 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -456,6 +456,11 @@ typedef struct _NMDeviceClass { guint32 (* get_dhcp_timeout) (NMDevice *self, int addr_family); + + /* Controls, whether to call act_stage2_config() callback also for assuming + * a device or for external activations. In this case, act_stage2_config() must + * take care not to touch the device's configuration. */ + bool act_stage2_config_also_for_external_or_assume:1; } NMDeviceClass; typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device, diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index a93854a465..1b0d39ed69 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -485,4 +485,8 @@ const char *nm_activation_type_to_string (NMActivationType activation_type); const char *nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing); +/*****************************************************************************/ + +#define NM_VPN_ROUTE_METRIC_DEFAULT 50 + #endif /* __NM_CORE_UTILS_H__ */ diff --git a/src/nm-policy.c b/src/nm-policy.c index cb0688f43b..540f406514 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -149,6 +149,25 @@ static NMDevice *get_default_device (NMPolicy *self, int addr_family); /*****************************************************************************/ +static void +_dns_manager_set_ip_config (NMDnsManager *dns_manager, + NMIPConfig *ip_config, + NMDnsIPConfigType ip_config_type, + NMDevice *device) +{ + if ( NM_IN_SET (ip_config_type, NM_DNS_IP_CONFIG_TYPE_DEFAULT, + NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) + && device + && nm_device_get_route_metric_default (nm_device_get_device_type (device)) == NM_VPN_ROUTE_METRIC_DEFAULT) { + /* some device types are inherently VPN. */ + ip_config_type = NM_DNS_IP_CONFIG_TYPE_VPN; + } + + nm_dns_manager_set_ip_config (dns_manager, ip_config, ip_config_type); +} + +/*****************************************************************************/ + typedef struct { NMPlatformIP6Address prefix; NMDevice *device; /* The requesting ("uplink") device */ @@ -1090,19 +1109,21 @@ update_ip_dns (NMPolicy *self, int addr_family) gpointer ip_config; const char *ip_iface = NULL; NMVpnConnection *vpn = NULL; + NMDevice *device = NULL; nm_assert_addr_family (addr_family); - ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, NULL, &vpn); + ip_config = get_best_ip_config (self, addr_family, &ip_iface, NULL, &device, &vpn); if (ip_config) { /* Tell the DNS manager this config is preferred by re-adding it with * a different IP config type. */ - nm_dns_manager_set_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, - ip_config, - vpn - ? NM_DNS_IP_CONFIG_TYPE_VPN - : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE); + _dns_manager_set_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, + ip_config, + vpn + ? NM_DNS_IP_CONFIG_TYPE_VPN + : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, + device); } if (addr_family == AF_INET6) @@ -1849,10 +1870,10 @@ device_state_changed (NMDevice *device, ip4_config = nm_device_get_ip4_config (device); if (ip4_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + _dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip4_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); ip6_config = nm_device_get_ip6_config (device); if (ip6_config) - nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT); + _dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); update_routing_and_dns (self, FALSE); @@ -1979,7 +2000,7 @@ device_ip_config_changed (NMDevice *device, if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { if (old_config != new_config) { if (new_config) - nm_dns_manager_set_ip_config (priv->dns_manager, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT); + _dns_manager_set_ip_config (priv->dns_manager, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); if (old_config) nm_dns_manager_set_ip_config (priv->dns_manager, old_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index ce96c18426..a7daebf821 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2371,8 +2371,9 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform, int wireguard_family_id, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers, + NMPlatformWireGuardChangeFlags change_flags, GPtrArray **out_msgs) { gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2384,6 +2385,7 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform, struct nlattr *nest_curr_peer; struct nlattr *nest_allowed_ips; struct nlattr *nest_curr_allowed_ip; + NMPlatformWireGuardChangePeerFlags p_flags = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT; #define _nla_nest_end(msg, nest_start) \ G_STMT_START { \ @@ -2418,12 +2420,19 @@ again: NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex); if (idx_peer_curr == IDX_NIL) { - NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key); - NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); - NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); + guint32 flags; - NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, - replace_peers ? WGDEVICE_F_REPLACE_PEERS : ((guint32) 0u)); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY)) + NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT)) + NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK)) + NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); + + flags = 0; + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS)) + flags |= WGDEVICE_F_REPLACE_PEERS; + NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, flags); } if (peers_len == 0) @@ -2442,6 +2451,21 @@ again: for (; idx_peer_curr < peers_len; idx_peer_curr++) { const NMPWireGuardPeer *p = &peers[idx_peer_curr]; + if (peer_flags) { + p_flags = peer_flags[idx_peer_curr]; + if (!NM_FLAGS_ANY (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS)) { + /* no flags set. We take that as indication to skip configuring the peer + * entirely. */ + nm_assert (p_flags == NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE); + continue; + } + } + nest_curr_peer = nla_nest_start (msg, 0); if (!nest_curr_peer) goto toobig_peers; @@ -2449,63 +2473,77 @@ again: if (nla_put (msg, WGPEER_A_PUBLIC_KEY, NMP_WIREGUARD_PUBLIC_KEY_LEN, p->public_key) < 0) goto toobig_peers; - if (idx_allowed_ips_curr == IDX_NIL) { - - if (nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0) - goto toobig_peers; - - if (nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0) + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME)) { + /* all other p_flags are silently ignored. */ + if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REMOVE_ME) < 0) goto toobig_peers; + } else { - if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) - goto toobig_peers; + if (idx_allowed_ips_curr == IDX_NIL) { + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY) + && nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0) + goto toobig_peers; - if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { - if (nla_put (msg, - WGPEER_A_ENDPOINT, - p->endpoint.sa.sa_family == AF_INET - ? sizeof (p->endpoint.in) - : sizeof (p->endpoint.in6), - &p->endpoint) < 0) + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL) + && nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0) goto toobig_peers; - } else - nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); - } - if (p->allowed_ips_len > 0) { - if (idx_allowed_ips_curr == IDX_NIL) - idx_allowed_ips_curr = 0; + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS) + && nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) + goto toobig_peers; - nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS); - if (!nest_allowed_ips) - goto toobig_allowedips; + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT)) { + if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { + if (nla_put (msg, + WGPEER_A_ENDPOINT, + p->endpoint.sa.sa_family == AF_INET + ? sizeof (p->endpoint.in) + : sizeof (p->endpoint.in6), + &p->endpoint) < 0) + goto toobig_peers; + } else { + /* I think there is no way to clear an endpoint, though there shold be. */ + nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); + } + } + } - for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { - const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS) + && p->allowed_ips_len > 0) { + if (idx_allowed_ips_curr == IDX_NIL) + idx_allowed_ips_curr = 0; - nest_curr_allowed_ip = nla_nest_start (msg, 0); - if (!nest_curr_allowed_ip) + nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS); + if (!nest_allowed_ips) goto toobig_allowedips; - g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG); + for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { + const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; - if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) - goto toobig_allowedips; - if (nla_put (msg, - WGALLOWEDIP_A_IPADDR, - nm_utils_addr_family_to_size (aip->family), - &aip->addr) < 0) - goto toobig_allowedips; - if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) - goto toobig_allowedips; + nest_curr_allowed_ip = nla_nest_start (msg, 0); + if (!nest_curr_allowed_ip) + goto toobig_allowedips; - _nla_nest_end (msg, nest_curr_allowed_ip); - nest_curr_allowed_ip = NULL; - } - idx_allowed_ips_curr = IDX_NIL; + g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG); + + if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) + goto toobig_allowedips; + if (nla_put (msg, + WGALLOWEDIP_A_IPADDR, + nm_utils_addr_family_to_size (aip->family), + &aip->addr) < 0) + goto toobig_allowedips; + if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) + goto toobig_allowedips; - _nla_nest_end (msg, nest_allowed_ips); - nest_allowed_ips = NULL; + _nla_nest_end (msg, nest_curr_allowed_ip); + nest_curr_allowed_ip = NULL; + } + idx_allowed_ips_curr = IDX_NIL; + + _nla_nest_end (msg, nest_allowed_ips); + nest_allowed_ips = NULL; + } } _nla_nest_end (msg, nest_curr_peer); @@ -2553,8 +2591,9 @@ link_wireguard_change (NMPlatform *platform, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers) + NMPlatformWireGuardChangeFlags change_flags) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2571,8 +2610,9 @@ link_wireguard_change (NMPlatform *platform, wireguard_family_id, lnk_wireguard, peers, + peer_flags, peers_len, - replace_peers, + change_flags, &msgs); if (r < 0) { _LOGW ("wireguard: set-device, cannot construct netlink message: %s", nm_strerror (r)); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 021b45d73e..10bf417968 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1982,6 +1982,24 @@ nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatf /*****************************************************************************/ +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_flags_to_string, NMPlatformWireGuardChangeFlags, + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS, "replace-peers"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY, "has-private-key"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT, "has-listen-port"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK, "has-fwmark"), +); + +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_peer_flags_to_string, NMPlatformWireGuardChangePeerFlags, + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME, "remove"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY, "psk"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL, "ka"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT, "ep"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, "aips"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS, "remove-aips"), +); + int nm_platform_link_wireguard_add (NMPlatform *self, const char *name, @@ -1995,8 +2013,9 @@ nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers) + NMPlatformWireGuardChangeFlags change_flags) { _CHECK_SELF (self, klass, -NME_BUG); @@ -2005,6 +2024,7 @@ nm_platform_link_wireguard_change (NMPlatform *self, if (_LOGD_ENABLED ()) { char buf_lnk[256]; char buf_peers[512]; + char buf_change_flags[100]; buf_peers[0] = '\0'; if (peers_len > 0) { @@ -2017,25 +2037,31 @@ nm_platform_link_wireguard_change (NMPlatform *self, nm_utils_strbuf_append_str (&b, &len, " { "); nm_platform_wireguard_peer_to_string (&peers[i], b, len); nm_utils_strbuf_seek_end (&b, &len); + if (peer_flags) { + nm_utils_strbuf_append (&b, &len, + " (%s)", + _wireguard_change_peer_flags_to_string (peer_flags[i], buf_change_flags, sizeof (buf_change_flags))); + } nm_utils_strbuf_append_str (&b, &len, " } "); } nm_utils_strbuf_append_str (&b, &len, "}"); } - _LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s%s", + _LOG3D ("link: change wireguard ifindex %d, %s, (%s), %u peers%s", ifindex, nm_platform_lnk_wireguard_to_string (lnk_wireguard, buf_lnk, sizeof (buf_lnk)), + _wireguard_change_flags_to_string (change_flags, buf_change_flags, sizeof (buf_change_flags)), peers_len, - buf_peers, - replace_peers ? " (replace-peers)" : " (update-peers)"); + buf_peers); } return klass->link_wireguard_change (self, ifindex, lnk_wireguard, peers, + peer_flags, peers_len, - replace_peers); + change_flags); } /*****************************************************************************/ @@ -5607,6 +5633,7 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g char s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100]; char s_endpoint[20 + sizeof (s_sockaddr)]; char s_addr[NM_UTILS_INET_ADDRSTRLEN]; + char s_keepalive[100]; guint i; nm_utils_to_string_buffer_init (&buf, &len); @@ -5624,10 +5651,11 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g nm_utils_strbuf_append (&buf, &len, "public-key %s" - "%s" /* preshared-key */ - "%s" /* endpoint */ + "%s" /* preshared-key */ + "%s" /* endpoint */ " rx %"G_GUINT64_FORMAT " tx %"G_GUINT64_FORMAT + "%s" /* persistent-keepalive */ "%s", /* allowed-ips */ public_key_b64, nm_utils_memeqzero (peer->preshared_key, sizeof (peer->preshared_key)) @@ -5636,6 +5664,9 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g s_endpoint, peer->rx_bytes, peer->tx_bytes, + peer->persistent_keepalive_interval > 0 + ? nm_sprintf_buf (s_keepalive, " keepalive %u", (guint) peer->persistent_keepalive_interval) + : "", peer->allowed_ips_len > 0 ? " allowed-ips" : ""); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 568b1f4b46..37aa58fdc5 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -748,11 +748,35 @@ typedef enum { } NMPlatformLinkDuplexType; typedef enum { - NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS = (1LL << 0), - NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL = (1LL << 1), - NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF = (1LL << 2), + NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS = (1LL << 0), + NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL = (1LL << 1), + NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF = (1LL << 2), } NMPlatformKernelSupportFlags; +typedef enum { + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE = 0, + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS = (1LL << 0), + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY = (1LL << 1), + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT = (1LL << 2), + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK = (1LL << 3), +} NMPlatformWireGuardChangeFlags; + +typedef enum { + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE = 0, + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME = (1LL << 0), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY = (1LL << 1), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL = (1LL << 2), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT = (1LL << 3), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS = (1LL << 4), + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS = (1LL << 5), + + NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, + +} NMPlatformWireGuardChangePeerFlags; + /*****************************************************************************/ struct _NMPlatformPrivate; @@ -830,8 +854,9 @@ typedef struct { int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers); + NMPlatformWireGuardChangeFlags change_flags); gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); gboolean (*link_vlan_change) (NMPlatform *self, @@ -1393,8 +1418,9 @@ int nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers); + NMPlatformWireGuardChangeFlags change_flags); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index e11858d634..71324301c7 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -912,8 +912,12 @@ _test_wireguard_change (NMPlatform *platform, ifindex, &lnk_wireguard, (const NMPWireGuardPeer *) peers->data, + NULL, peers->len, - TRUE); + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS); g_assert (NMTST_NM_ERR_SUCCESS (r)); } diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index 5482fb0d8b..e70590b248 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -28,8 +28,6 @@ #include "nm-active-connection.h" #include "nm-vpn-plugin-info.h" -#define NM_VPN_ROUTE_METRIC_DEFAULT 50 - #define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ()) #define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection)) #define NM_VPN_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_CONNECTION, NMVpnConnectionClass)) |