diff options
author | Thomas Haller <thaller@redhat.com> | 2019-01-22 16:31:22 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-01-22 16:31:59 +0100 |
commit | 81da34eb1e9e212653c7ab5a0505b455361369ee (patch) | |
tree | 6871dcfb92323a2c0d75a2032af18a89bde1a9f6 | |
parent | d7d2dafc1b25bc02a51c32e9660b66e4a987befe (diff) | |
parent | 69ce5def413b72c108fc11cdd9ffec53d74ea66e (diff) | |
download | NetworkManager-81da34eb1e9e212653c7ab5a0505b455361369ee.tar.gz |
all: merge branch 'th/various-for-wireguard-1'
https://github.com/NetworkManager/NetworkManager/pull/282
-rw-r--r-- | libnm-core/nm-connection.c | 43 | ||||
-rw-r--r-- | libnm-core/nm-setting-private.h | 7 | ||||
-rw-r--r-- | libnm-core/nm-setting-vpn.c | 52 | ||||
-rw-r--r-- | libnm-core/nm-setting.c | 312 | ||||
-rw-r--r-- | libnm-core/nm-setting.h | 17 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.h | 10 | ||||
-rw-r--r-- | shared/nm-utils/tests/test-shared-general.c | 53 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 62 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 40 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 6 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 199 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 26 | ||||
-rw-r--r-- | src/platform/tests/test-link.c | 3 |
13 files changed, 539 insertions, 291 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index c2b2ae0b56..724e8557b8 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -102,10 +102,16 @@ setting_changed_cb (NMSetting *setting, g_signal_emit (self, signals[CHANGED], 0); } +static void +_setting_release (NMConnection *connection, NMSetting *setting) +{ + g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, connection); +} + static gboolean -_setting_release (gpointer key, gpointer value, gpointer user_data) +_setting_release_hfr (gpointer key, gpointer value, gpointer user_data) { - g_signal_handlers_disconnect_by_func (user_data, setting_changed_cb, value); + _setting_release (user_data, value); return TRUE; } @@ -123,9 +129,10 @@ _nm_connection_add_setting (NMConnection *connection, NMSetting *setting) setting_type = G_OBJECT_TYPE (setting); if ((s_old = g_hash_table_lookup (priv->settings, _gtype_to_hash_key (setting_type)))) - g_signal_handlers_disconnect_by_func (s_old, setting_changed_cb, connection); + _setting_release (connection, s_old); + g_hash_table_insert (priv->settings, _gtype_to_hash_key (setting_type), setting); - /* Listen for property changes so we can emit the 'changed' signal */ + g_signal_connect (setting, "notify", (GCallback) setting_changed_cb, connection); } @@ -409,7 +416,7 @@ _nm_connection_replace_settings (NMConnection *connection, } if (g_hash_table_size (priv->settings) > 0) { - g_hash_table_foreach_remove (priv->settings, _setting_release, connection); + g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection); changed = TRUE; } else changed = (settings != NULL); @@ -494,7 +501,7 @@ nm_connection_replace_settings_from_connection (NMConnection *connection, new_priv = NM_CONNECTION_GET_PRIVATE (new_connection); if ((changed = g_hash_table_size (priv->settings) > 0)) - g_hash_table_foreach_remove (priv->settings, _setting_release, connection); + g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection); if (g_hash_table_size (new_priv->settings)) { g_hash_table_iter_init (&iter, new_priv->settings); @@ -523,7 +530,7 @@ nm_connection_clear_settings (NMConnection *connection) priv = NM_CONNECTION_GET_PRIVATE (connection); if (g_hash_table_size (priv->settings) > 0) { - g_hash_table_foreach_remove (priv->settings, _setting_release, connection); + g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection); g_signal_emit (connection, signals[CHANGED], 0); } } @@ -1832,26 +1839,14 @@ nm_connection_need_secrets (NMConnection *connection, void nm_connection_clear_secrets (NMConnection *connection) { - GHashTableIter iter; - NMSetting *setting; - - g_return_if_fail (NM_IS_CONNECTION (connection)); - - g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) { - g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection); - _nm_setting_clear_secrets (setting); - g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection); - } - - g_signal_emit (connection, signals[SECRETS_CLEARED], 0); + return nm_connection_clear_secrets_with_flags (connection, NULL, NULL); } /** * nm_connection_clear_secrets_with_flags: * @connection: the #NMConnection - * @func: (scope call): function to be called to determine whether a - * specific secret should be cleared or not + * @func: (scope call): (allow-none): function to be called to determine whether a + * specific secret should be cleared or not. If %NULL, all secrets are cleared. * @user_data: caller-supplied data passed to @func * * Clears and frees secrets determined by @func. @@ -1869,7 +1864,7 @@ nm_connection_clear_secrets_with_flags (NMConnection *connection, g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) { g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection); - _nm_setting_clear_secrets_with_flags (setting, func, user_data); + _nm_setting_clear_secrets (setting, func, user_data); g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection); } @@ -2973,7 +2968,7 @@ nm_connection_private_free (NMConnectionPrivate *priv) { NMConnection *self = priv->self; - g_hash_table_foreach_remove (priv->settings, _setting_release, self); + g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, self); g_hash_table_destroy (priv->settings); g_free (priv->path); diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h index 2f46bc6770..8f61b0ff9d 100644 --- a/libnm-core/nm-setting-private.h +++ b/libnm-core/nm-setting-private.h @@ -48,10 +48,9 @@ typedef enum NMSettingUpdateSecretResult { NMSettingUpdateSecretResult _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **error); -gboolean _nm_setting_clear_secrets (NMSetting *setting); -gboolean _nm_setting_clear_secrets_with_flags (NMSetting *setting, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data); +gboolean _nm_setting_clear_secrets (NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data); /* The property of the #NMSetting should be considered during comparisons that * use the %NM_SETTING_COMPARE_FLAG_INFERRABLE flag. Properties that don't have diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c index 62ed373df7..1371140ec4 100644 --- a/libnm-core/nm-setting-vpn.c +++ b/libnm-core/nm-setting-vpn.c @@ -813,29 +813,43 @@ compare_property (const NMSettInfoSetting *sett_info, } static gboolean -clear_secrets_with_flags (NMSetting *setting, - GParamSpec *pspec, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data) +clear_secrets (const NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data) { NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting); + GParamSpec *prop_spec = sett_info->property_infos[property_idx].param_spec; GHashTableIter iter; const char *secret; gboolean changed = TRUE; - if (priv->secrets == NULL) + if ( !prop_spec + || !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET)) + return FALSE; + + nm_assert (nm_streq (prop_spec->name, NM_SETTING_VPN_SECRETS)); + + if (!priv->secrets) return FALSE; - /* Iterate through secrets hash and check each entry */ g_hash_table_iter_init (&iter, priv->secrets); while (g_hash_table_iter_next (&iter, (gpointer) &secret, NULL)) { - NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; - nm_setting_get_secret_flags (setting, secret, &flags, NULL); - if (func (setting, pspec->name, flags, user_data) == TRUE) { - g_hash_table_iter_remove (&iter); - changed = TRUE; - } + if (func) { + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + + if (!nm_setting_get_secret_flags (setting, secret, &flags, NULL)) + nm_assert_not_reached (); + + if (!func (setting, secret, flags, user_data)) + continue; + } else + nm_assert (nm_setting_get_secret_flags (setting, secret, NULL, NULL)); + + g_hash_table_iter_remove (&iter); + changed = TRUE; } if (changed) @@ -963,13 +977,13 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass) object_class->set_property = set_property; object_class->finalize = finalize; - setting_class->verify = verify; - setting_class->update_one_secret = update_one_secret; - setting_class->get_secret_flags = get_secret_flags; - setting_class->set_secret_flags = set_secret_flags; - setting_class->need_secrets = need_secrets; - setting_class->compare_property = compare_property; - setting_class->clear_secrets_with_flags = clear_secrets_with_flags; + setting_class->verify = verify; + setting_class->update_one_secret = update_one_secret; + setting_class->get_secret_flags = get_secret_flags; + setting_class->set_secret_flags = set_secret_flags; + setting_class->need_secrets = need_secrets; + setting_class->compare_property = compare_property; + setting_class->clear_secrets = clear_secrets; /** * NMSettingVpn:service-type: diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index d12f9ea7e8..976f7f0085 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -539,12 +539,16 @@ _nm_sett_info_setting_get_property_info (const NMSettInfoSetting *sett_info, const NMSettInfoSetting * _nm_setting_class_get_sett_info (NMSettingClass *setting_class) { - if ( NM_IS_SETTING_CLASS (setting_class) - && setting_class->setting_info) { - nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings)); - return &_sett_info_settings[setting_class->setting_info->meta_type]; - } - return NULL; + const NMSettInfoSetting *sett_info; + + if ( !NM_IS_SETTING_CLASS (setting_class) + || !setting_class->setting_info) + return NULL; + + nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings)); + sett_info = &_sett_info_settings[setting_class->setting_info->meta_type]; + nm_assert (sett_info->setting_class == setting_class); + return sett_info; } /*****************************************************************************/ @@ -876,89 +880,94 @@ _nm_setting_new_from_dbus (GType setting_type, } for (i = 0; i < sett_info->property_infos_len; i++) { - const NMSettInfoProperty *property = &sett_info->property_infos[i]; + const NMSettInfoProperty *property_info = &sett_info->property_infos[i]; gs_unref_variant GVariant *value = NULL; gs_free_error GError *local = NULL; - if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE)) + if ( property_info->param_spec + && !(property_info->param_spec->flags & G_PARAM_WRITABLE)) continue; - value = g_variant_lookup_value (setting_dict, property->name, NULL); + value = g_variant_lookup_value (setting_dict, property_info->name, NULL); if (value && keys) - g_hash_table_remove (keys, property->name); + g_hash_table_remove (keys, property_info->name); - if (value && property->set_func) { + if ( value + && property_info->set_func) { - if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) { + if (!g_variant_type_equal (g_variant_get_type (value), property_info->dbus_type)) { /* for backward behavior, fail unless best-effort is chosen. */ if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)) continue; g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("can't set property of type '%s' from value of type '%s'"), - property->dbus_type ? - g_variant_type_peek_string (property->dbus_type) : - property->param_spec ? - g_type_name (property->param_spec->value_type) : "(unknown)", + property_info->dbus_type ? + g_variant_type_peek_string (property_info->dbus_type) : + property_info->param_spec ? + g_type_name (property_info->param_spec->value_type) : "(unknown)", g_variant_get_type_string (value)); - g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - if (!property->set_func (setting, - connection_dict, - property->name, - value, - parse_flags, - &local)) { + if (!property_info->set_func (setting, + connection_dict, + property_info->name, + value, + parse_flags, + &local)) { if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) continue; g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("failed to set property: %s"), local->message); - g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - } else if (!value && property->not_set_func) { - if (!property->not_set_func (setting, - connection_dict, - property->name, - parse_flags, - &local)) { + } else if ( !value + && property_info->not_set_func) { + if (!property_info->not_set_func (setting, + connection_dict, + property_info->name, + parse_flags, + &local)) { if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) continue; g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("failed to set property: %s"), local->message); - g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - } else if (value && property->param_spec) { + } else if ( value + && property_info->param_spec) { nm_auto_unset_gvalue GValue object_value = G_VALUE_INIT; - g_value_init (&object_value, property->param_spec->value_type); - if (!set_property_from_dbus (property, value, &object_value)) { + g_value_init (&object_value, property_info->param_spec->value_type); + if (!set_property_from_dbus (property_info, value, &object_value)) { /* for backward behavior, fail unless best-effort is chosen. */ if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)) continue; g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("can't set property of type '%s' from value of type '%s'"), - property->dbus_type ? - g_variant_type_peek_string (property->dbus_type) : - property->param_spec ? - g_type_name (property->param_spec->value_type) : "(unknown)", + property_info->dbus_type + ? g_variant_type_peek_string (property_info->dbus_type) + : ( property_info->param_spec + ? g_type_name (property_info->param_spec->value_type) + : "(unknown)"), g_variant_get_type_string (value)); - g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - if (!nm_g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value, &local)) { + if (!nm_g_object_set_property (G_OBJECT (setting), property_info->param_spec->name, &object_value, &local)) { if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) continue; g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("can not set property: %s"), local->message); - g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } } @@ -1065,34 +1074,18 @@ _gobject_copy_property (GObject *src, g_object_set_property (dst, property_name, &value); } -/** - * nm_setting_duplicate: - * @setting: the #NMSetting to duplicate - * - * Duplicates a #NMSetting. - * - * Returns: (transfer full): a new #NMSetting containing the same properties and values as the - * source #NMSetting - **/ -NMSetting * -nm_setting_duplicate (NMSetting *setting) +static void +duplicate_copy_properties (const NMSettInfoSetting *sett_info, + NMSetting *src, + NMSetting *dst) { - const NMSettInfoSetting *sett_info; - GObject *dup; - - g_return_val_if_fail (NM_IS_SETTING (setting), NULL); - - dup = g_object_new (G_OBJECT_TYPE (setting), NULL); - - sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); - if (sett_info->detail.gendata_info) { - GenData *gendata = _gendata_hash (setting, FALSE); + GenData *gendata = _gendata_hash (src, FALSE); if ( gendata && g_hash_table_size (gendata->hash) > 0) { GHashTableIter iter; - GHashTable *h = _gendata_hash (NM_SETTING (dup), TRUE)->hash; + GHashTable *h = _gendata_hash (dst, TRUE)->hash; const char *key; GVariant *val; @@ -1110,29 +1103,58 @@ nm_setting_duplicate (NMSetting *setting) guint i; for (i = 0; i < sett_info->property_infos_len; i++) { - GParamSpec *prop_spec = sett_info->property_infos[i].param_spec; + const NMSettInfoProperty *property_info = &sett_info->property_infos[i]; - if (!prop_spec) - continue; - if ((prop_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE) - continue; + if (property_info->param_spec) { + if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE) + continue; - if (!frozen) { - g_object_freeze_notify (dup); - frozen = TRUE; + if (!frozen) { + g_object_freeze_notify (G_OBJECT (dst)); + frozen = TRUE; + } + _gobject_copy_property (G_OBJECT (src), + G_OBJECT (dst), + property_info->param_spec->name, + G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec)); + continue; } - - _gobject_copy_property (G_OBJECT (setting), - dup, - prop_spec->name, - G_PARAM_SPEC_VALUE_TYPE (prop_spec)); } if (frozen) - g_object_thaw_notify (dup); + g_object_thaw_notify (G_OBJECT (dst)); } +} + +/** + * nm_setting_duplicate: + * @setting: the #NMSetting to duplicate + * + * Duplicates a #NMSetting. + * + * Returns: (transfer full): a new #NMSetting containing the same properties and values as the + * source #NMSetting + **/ +NMSetting * +nm_setting_duplicate (NMSetting *setting) +{ + const NMSettInfoSetting *sett_info; + NMSettingClass *klass; + NMSetting *dst; + + g_return_val_if_fail (NM_IS_SETTING (setting), NULL); + + klass = NM_SETTING_GET_CLASS (setting); + nm_assert (NM_IS_SETTING_CLASS (klass)); + nm_assert (klass->duplicate_copy_properties); - return NM_SETTING (dup); + dst = g_object_new (G_TYPE_FROM_CLASS (klass), NULL); + + sett_info = _nm_setting_class_get_sett_info (klass); + nm_assert (sett_info); + + klass->duplicate_copy_properties (sett_info, setting, dst); + return dst; } /** @@ -1818,81 +1840,47 @@ _nm_setting_aggregate (NMSetting *setting, return FALSE; } -/** - * _nm_setting_clear_secrets: - * @setting: the #NMSetting - * - * Resets and clears any secrets in the setting. Secrets should be added to the - * setting only when needed, and cleared immediately after use to prevent - * leakage of information. - * - * Returns: %TRUE if the setting changed at all - **/ -gboolean -_nm_setting_clear_secrets (NMSetting *setting) -{ - const NMSettInfoSetting *sett_info; - gboolean changed = FALSE; - guint i; - - g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); - - sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); - for (i = 0; i < sett_info->property_infos_len; i++) { - GParamSpec *prop_spec = sett_info->property_infos[i].param_spec; - - if (!prop_spec) - continue; - - if (prop_spec->flags & NM_SETTING_PARAM_SECRET) { - GValue value = G_VALUE_INIT; - - g_value_init (&value, prop_spec->value_type); - g_object_get_property (G_OBJECT (setting), prop_spec->name, &value); - if (!g_param_value_defaults (prop_spec, &value)) { - g_param_value_set_default (prop_spec, &value); - g_object_set_property (G_OBJECT (setting), prop_spec->name, &value); - changed = TRUE; - } - g_value_unset (&value); - } - } - return changed; -} - static gboolean -clear_secrets_with_flags (NMSetting *setting, - GParamSpec *pspec, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data) +clear_secrets (const NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data) { NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; - gboolean changed = FALSE; + GParamSpec *param_spec = sett_info->property_infos[property_idx].param_spec; - g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE); + if (!param_spec) + return FALSE; - /* Clear the secret if the user function says to do so */ - if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL)) - g_return_val_if_reached (FALSE); + if (!NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET)) + return FALSE; - if (func (setting, pspec->name, flags, user_data) == TRUE) { - GValue value = G_VALUE_INIT; + if (func) { + if (!nm_setting_get_secret_flags (setting, param_spec->name, &flags, NULL)) + nm_assert_not_reached (); + if (!func (setting, param_spec->name, flags, user_data)) + return FALSE; + } else + nm_assert (nm_setting_get_secret_flags (setting, param_spec->name, NULL, NULL)); - g_value_init (&value, pspec->value_type); - g_object_get_property (G_OBJECT (setting), pspec->name, &value); - if (!g_param_value_defaults (pspec, &value)) { - g_param_value_set_default (pspec, &value); - g_object_set_property (G_OBJECT (setting), pspec->name, &value); - changed = TRUE; - } - g_value_unset (&value); + { + nm_auto_unset_gvalue GValue value = G_VALUE_INIT; + + g_value_init (&value, param_spec->value_type); + g_object_get_property (G_OBJECT (setting), param_spec->name, &value); + if (g_param_value_defaults (param_spec, &value)) + return FALSE; + + g_param_value_set_default (param_spec, &value); + g_object_set_property (G_OBJECT (setting), param_spec->name, &value); } - return changed; + return TRUE; } /** - * _nm_setting_clear_secrets_with_flags: + * _nm_setting_clear_secrets: * @setting: the #NMSetting * @func: (scope call): function to be called to determine whether a * specific secret should be cleared or not @@ -1903,31 +1891,30 @@ clear_secrets_with_flags (NMSetting *setting, * Returns: %TRUE if the setting changed at all **/ gboolean -_nm_setting_clear_secrets_with_flags (NMSetting *setting, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data) +_nm_setting_clear_secrets (NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data) { const NMSettInfoSetting *sett_info; gboolean changed = FALSE; guint i; + gboolean (*my_clear_secrets) (const struct _NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data); g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); - g_return_val_if_fail (func != NULL, FALSE); + + my_clear_secrets = NM_SETTING_GET_CLASS (setting)->clear_secrets; sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); for (i = 0; i < sett_info->property_infos_len; i++) { - GParamSpec *prop_spec = sett_info->property_infos[i].param_spec; - - if (!prop_spec) - continue; - - if (!NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET)) - continue; - - changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting, - prop_spec, - func, - user_data); + changed |= my_clear_secrets (sett_info, + i, + setting, + func, + user_data); } return changed; } @@ -2579,11 +2566,12 @@ nm_setting_class_init (NMSettingClass *setting_class) object_class->get_property = get_property; object_class->finalize = finalize; - setting_class->update_one_secret = update_one_secret; - setting_class->get_secret_flags = get_secret_flags; - setting_class->set_secret_flags = set_secret_flags; - setting_class->compare_property = compare_property; - setting_class->clear_secrets_with_flags = clear_secrets_with_flags; + setting_class->update_one_secret = update_one_secret; + setting_class->get_secret_flags = get_secret_flags; + setting_class->set_secret_flags = set_secret_flags; + setting_class->compare_property = compare_property; + setting_class->clear_secrets = clear_secrets; + setting_class->duplicate_copy_properties = duplicate_copy_properties; /** * NMSetting:name: diff --git a/libnm-core/nm-setting.h b/libnm-core/nm-setting.h index 326b533f12..0f0ac8f382 100644 --- a/libnm-core/nm-setting.h +++ b/libnm-core/nm-setting.h @@ -200,10 +200,12 @@ typedef struct { NMSettingSecretFlags flags, GError **error); - gboolean (*clear_secrets_with_flags) (NMSetting *setting, - GParamSpec *pspec, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data); + /*< private >*/ + gboolean (*clear_secrets) (const struct _NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data); /* compare_property() returns a ternary, where DEFAULT means that the property should not * be compared due to the compare @flags. A TRUE/FALSE result means that the property is @@ -219,10 +221,15 @@ typedef struct { NMSettingCompareFlags flags); /*< private >*/ + void (*duplicate_copy_properties) (const struct _NMSettInfoSetting *sett_info, + NMSetting *src, + NMSetting *dst); + + /*< private >*/ const struct _NMMetaSettingInfo *setting_info; /*< private >*/ - gpointer padding[6]; + gpointer padding[5]; } NMSettingClass; /** diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 8106371d0a..e28a5fb2f3 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -102,6 +102,7 @@ typedef struct { union { guint8 addr_ptr[1]; in_addr_t addr4; + struct in_addr addr4_struct; struct in6_addr addr6; /* NMIPAddr is really a union for IP addresses. @@ -255,10 +256,12 @@ nm_memdup (gconstpointer data, gsize size) static inline char * _nm_strndup_a_step (char *s, const char *str, gsize len) { + NM_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation"); if (len > 0) strncpy (s, str, len); s[len] = '\0'; return s; + NM_PRAGMA_WARNING_REENABLE; } /* Similar to g_strndup(), however, if the string (including the terminating @@ -269,7 +272,12 @@ _nm_strndup_a_step (char *s, const char *str, gsize len) * * In case malloc() is necessary, @out_str_free will be set (this string * must be freed afterwards). It is permissible to pass %NULL as @out_str_free, - * if you ensure that len < alloca_maxlen. */ + * if you ensure that len < alloca_maxlen. + * + * Note that just like g_strndup(), this always returns a buffer with @len + 1 + * bytes, even if strlen(@str) is shorter than that (NUL terminated early). We fill + * the buffer with strncpy(), which means, that @str is copied up to the first + * NUL character and then filled with NUL characters. */ #define nm_strndup_a(alloca_maxlen, str, len, out_str_free) \ ({ \ const gsize _alloca_maxlen = (alloca_maxlen); \ diff --git a/shared/nm-utils/tests/test-shared-general.c b/shared/nm-utils/tests/test-shared-general.c index d7df46dc52..7d22e56d99 100644 --- a/shared/nm-utils/tests/test-shared-general.c +++ b/shared/nm-utils/tests/test-shared-general.c @@ -152,6 +152,58 @@ test_nm_strdup_int (void) /*****************************************************************************/ +static void +test_nm_strndup_a (void) +{ + int run; + + for (run = 0; run < 20; run++) { + gs_free char *input = NULL; + char ch; + gsize i, l; + + input = g_strnfill (nmtst_get_rand_int () % 20, 'x'); + + for (i = 0; input[i]; i++) { + while ((ch = ((char) nmtst_get_rand_int ())) == '\0') { + /* repeat. */ + } + input[i] = ch; + } + + { + gs_free char *dup_free = NULL; + const char *dup; + + l = strlen (input) + 1; + dup = nm_strndup_a (10, input, l - 1, &dup_free); + g_assert_cmpstr (dup, ==, input); + if (strlen (dup) < 10) + g_assert (!dup_free); + else + g_assert (dup == dup_free); + } + + { + gs_free char *dup_free = NULL; + const char *dup; + + l = nmtst_get_rand_int () % 23; + dup = nm_strndup_a (10, input, l, &dup_free); + g_assert (strncmp (dup, input, l) == 0); + g_assert (strlen (dup) <= l); + if (l < 10) + g_assert (!dup_free); + else + g_assert (dup == dup_free); + if (strlen (input) < l) + g_assert (nm_utils_memeqzero (&dup[strlen (input)], l - strlen (input))); + } + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -162,6 +214,7 @@ int main (int argc, char **argv) g_test_add_func ("/general/test_nmhash", test_nmhash); g_test_add_func ("/general/test_nm_make_strv", test_make_strv); g_test_add_func ("/general/test_nm_strdup_int", test_nm_strdup_int); + g_test_add_func ("/general/test_nm_strndup_a", test_nm_strndup_a); return g_test_run (); } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 7db6a9261e..85214ec854 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -482,30 +482,6 @@ static struct nl_sock *_genl_sock (NMLinuxPlatform *platform); /*****************************************************************************/ static int -_sock_addr_set_unaligned (NMSockAddrUnion *dst, - gconstpointer src, - gsize src_len) -{ - int f_expected; - struct sockaddr sa; - - if (src_len == sizeof (struct sockaddr_in)) - f_expected = AF_INET; - else if (src_len == sizeof (struct sockaddr_in6)) - f_expected = AF_INET6; - else - return AF_UNSPEC; - - memcpy (&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof (sa.sa_family)); - if (sa.sa_family != f_expected) - return AF_UNSPEC; - memcpy (dst, src, src_len); - return f_expected; -} - -/*****************************************************************************/ - -static int wait_for_nl_response_to_nmerr (WaitForNlResponseResult seq_result) { if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) @@ -2038,11 +2014,11 @@ _wireguard_update_from_peers_nla (CList *peers, nm_explicit_bzero (nla_data (tb[WGPEER_A_PRESHARED_KEY]), nla_len (tb[WGPEER_A_PRESHARED_KEY])); } - if (tb[WGPEER_A_ENDPOINT]) { - _sock_addr_set_unaligned (&peer_c->data.endpoint, - nla_data (tb[WGPEER_A_ENDPOINT]), - nla_len (tb[WGPEER_A_ENDPOINT])); - } + + nm_sock_addr_union_cpy_untrusted (&peer_c->data.endpoint, + tb[WGPEER_A_ENDPOINT] ? nla_data (tb[WGPEER_A_ENDPOINT]) : NULL, + tb[WGPEER_A_ENDPOINT] ? nla_len (tb[WGPEER_A_ENDPOINT]) : 0); + if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) @@ -2398,6 +2374,7 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, guint peers_len, + gboolean replace_peers, GPtrArray **out_msgs) { gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2446,7 +2423,9 @@ again: 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); - NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, WGDEVICE_F_REPLACE_PEERS); + + NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, + replace_peers ? WGDEVICE_F_REPLACE_PEERS : ((guint32) 0u)); } if (peers_len == 0) @@ -2483,15 +2462,16 @@ again: if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) goto toobig_peers; - g_return_val_if_fail (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6), -NME_BUG); - - 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; + 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 + nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); } if (p->allowed_ips_len > 0) { @@ -2575,7 +2555,8 @@ link_wireguard_change (NMPlatform *platform, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, - guint peers_len) + guint peers_len, + gboolean replace_peers) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2593,6 +2574,7 @@ link_wireguard_change (NMPlatform *platform, lnk_wireguard, peers, peers_len, + replace_peers, &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 bebb6ad3dc..4bb31b1742 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1997,8 +1997,9 @@ int nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, - const struct _NMPWireGuardPeer *peers, - guint peers_len) + const NMPWireGuardPeer *peers, + guint peers_len, + gboolean replace_peers) { _CHECK_SELF (self, klass, -NME_BUG); @@ -2024,18 +2025,20 @@ nm_platform_link_wireguard_change (NMPlatform *self, nm_utils_strbuf_append_str (&b, &len, "}"); } - _LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s", + _LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s%s", ifindex, nm_platform_lnk_wireguard_to_string (lnk_wireguard, buf_lnk, sizeof (buf_lnk)), peers_len, - buf_peers); + buf_peers, + replace_peers ? " (replace-peers)" : " (update-peers)"); } return klass->link_wireguard_change (self, ifindex, lnk_wireguard, peers, - peers_len); + peers_len, + replace_peers); } /*****************************************************************************/ @@ -5604,33 +5607,24 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g { char *buf0 = buf; gs_free char *public_key_b64 = NULL; - char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100]; + char s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100]; + char s_endpoint[20 + sizeof (s_sockaddr)]; char s_addr[NM_UTILS_INET_ADDRSTRLEN]; - char s_scope_id[40]; guint i; nm_utils_to_string_buffer_init (&buf, &len); - if (peer->endpoint.sa.sa_family == AF_INET) { - nm_sprintf_buf (s_endpoint, - " endpoint %s:%u", - nm_utils_inet4_ntop (peer->endpoint.in.sin_addr.s_addr, s_addr), - (guint) htons (peer->endpoint.in.sin_port)); - } else if (peer->endpoint.sa.sa_family == AF_INET6) { - if (peer->endpoint.in6.sin6_scope_id != 0) - nm_sprintf_buf (s_scope_id, "@%u", peer->endpoint.in6.sin6_scope_id); - else - s_scope_id[0] = '\0'; + public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key)); + + if (peer->endpoint.sa.sa_family != AF_UNSPEC) { nm_sprintf_buf (s_endpoint, - " endpoint [%s]%s:%u", - nm_utils_inet6_ntop (&peer->endpoint.in6.sin6_addr, s_addr), - s_scope_id, - (guint) htons (peer->endpoint.in6.sin6_port)); + " endpoint %s", + nm_sock_addr_union_to_string (&peer->endpoint, + s_sockaddr, + sizeof (s_sockaddr))); } else s_endpoint[0] = '\0'; - public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key)); - nm_utils_strbuf_append (&buf, &len, "public-key %s" "%s" /* preshared-key */ diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 1f136da582..412ac597ab 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -831,7 +831,8 @@ typedef struct { int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, - guint peers_len); + guint peers_len, + gboolean replace_peers); gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); gboolean (*link_vlan_change) (NMPlatform *self, @@ -1393,7 +1394,8 @@ int nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, - guint peers_len); + guint peers_len, + gboolean replace_peers); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 03ddaaa7b3..80e65b494c 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -89,6 +89,192 @@ struct _NMPCache { /*****************************************************************************/ +int +nm_sock_addr_union_cmp (const NMSockAddrUnion *a, const NMSockAddrUnion *b) +{ + nm_assert (!a || NM_IN_SET (a->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6)); + nm_assert (!b || NM_IN_SET (b->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6)); + + NM_CMP_SELF (a, b); + + NM_CMP_FIELD (a, b, sa.sa_family); + switch (a->sa.sa_family) { + case AF_INET: + NM_CMP_DIRECT (ntohl (a->in.sin_addr.s_addr), ntohl (b->in.sin_addr.s_addr)); + NM_CMP_DIRECT (htons (a->in.sin_port), htons (b->in.sin_port)); + break; + case AF_INET6: + NM_CMP_DIRECT_IN6ADDR (&a->in6.sin6_addr, &b->in6.sin6_addr); + NM_CMP_DIRECT (htons (a->in6.sin6_port), htons (b->in6.sin6_port)); + NM_CMP_FIELD (a, b, in6.sin6_scope_id); + NM_CMP_FIELD (a, b, in6.sin6_flowinfo); + break; + } + return 0; +} + +void +nm_sock_addr_union_hash_update (const NMSockAddrUnion *a, NMHashState *h) +{ + if (!a) { + nm_hash_update_val (h, 1241364739u); + return; + } + + nm_assert (NM_IN_SET (a->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6)); + + switch (a->sa.sa_family) { + case AF_INET: + nm_hash_update_vals (h, + a->in.sin_family, + a->in.sin_addr.s_addr, + a->in.sin_port); + return; + case AF_INET6: + nm_hash_update_vals (h, + a->in6.sin6_family, + a->in6.sin6_addr, + a->in6.sin6_port, + a->in6.sin6_scope_id, + a->in6.sin6_flowinfo); + return; + default: + nm_hash_update_val (h, a->sa.sa_family); + return; + } +} + +/** + * nm_sock_addr_union_cpy: + * @dst: the destination #NMSockAddrUnion. It will always be fully initialized, + * to one of the address families AF_INET, AF_INET6, or AF_UNSPEC (in case of + * error). + * @src: (allow-none): the source buffer with an sockaddr to copy. It may be unaligned in + * memory. If not %NULL, the buffer must be at least large enough to contain + * sa.sa_family, and then, depending on sa.sa_family, it must be large enough + * to hold struct sockaddr_in or struct sockaddr_in6. + * + * @dst will always be fully initialized (including setting all un-used bytes to zero). + */ +void +nm_sock_addr_union_cpy (NMSockAddrUnion *dst, + gconstpointer src /* unaligned (const NMSockAddrUnion *) */) +{ + struct sockaddr sa; + gsize src_len; + + nm_assert (dst); + + *dst = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; + + if (!src) + return; + + memcpy (&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof (sa.sa_family)); + + if (sa.sa_family == AF_INET) + src_len = sizeof (struct sockaddr_in); + else if (sa.sa_family == AF_INET6) + src_len = sizeof (struct sockaddr_in6); + else + return; + + memcpy (dst, src, src_len); + nm_assert (dst->sa.sa_family == sa.sa_family); +} + +/** + * nm_sock_addr_union_cpy_untrusted: + * @dst: the destination #NMSockAddrUnion. It will always be fully initialized, + * to one of the address families AF_INET, AF_INET6, or AF_UNSPEC (in case of + * error). + * @src: the source buffer with an sockaddr to copy. It may be unaligned in + * memory. + * @src_len: the length of @src in bytes. + * + * The function requires @src_len to be either sizeof(struct sockaddr_in) or sizeof (struct sockaddr_in6). + * If that's the case, then @src will be interpreted as such structure (unaligned), and + * accessed. It will check sa.sa_family to match the expected sizes, and if it does, the + * struct will be copied. + * + * On any failure, @dst will be set to sa.sa_family AF_UNSPEC. + * @dst will always be fully initialized (including setting all un-used bytes to zero). + */ +void +nm_sock_addr_union_cpy_untrusted (NMSockAddrUnion *dst, + gconstpointer src /* unaligned (const NMSockAddrUnion *) */, + gsize src_len) +{ + int f_expected; + struct sockaddr sa; + + nm_assert (dst); + + *dst = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; + + if (src_len == sizeof (struct sockaddr_in)) + f_expected = AF_INET; + else if (src_len == sizeof (struct sockaddr_in6)) + f_expected = AF_INET6; + else + return; + + memcpy (&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof (sa.sa_family)); + + if (sa.sa_family != f_expected) + return; + + memcpy (dst, src, src_len); + nm_assert (dst->sa.sa_family == sa.sa_family); +} + +const char * +nm_sock_addr_union_to_string (const NMSockAddrUnion *sa, + char *buf, + gsize len) +{ + char s_addr[NM_UTILS_INET_ADDRSTRLEN]; + char s_scope_id[40]; + + if (!nm_utils_to_string_buffer_init_null (sa, &buf, &len)) + return buf; + + /* maybe we should use getnameinfo(), but here implement it ourself. + * + * We want to see the actual bytes for debugging (as we understand them), + * and now what getnameinfo() makes of it. Also, it's simpler this way. */ + + switch (sa->sa.sa_family) { + case AF_INET: + g_snprintf (buf, len, + "%s:%u", + nm_utils_inet4_ntop (sa->in.sin_addr.s_addr, s_addr), + (guint) htons (sa->in.sin_port)); + break; + case AF_INET6: + g_snprintf (buf, len, + "[%s%s]:%u", + nm_utils_inet6_ntop (&sa->in6.sin6_addr, s_addr), + ( sa->in6.sin6_scope_id != 0 + ? nm_sprintf_buf (s_scope_id, "%u", sa->in6.sin6_scope_id) + : ""), + (guint) htons (sa->in6.sin6_port)); + break; + case AF_UNSPEC: + g_snprintf (buf, len, "unspec"); + break; + default: + g_snprintf (buf, len, + "{addr-family:%u}", + (unsigned) sa->sa.sa_family); + break; + } + + return buf; +} + +/*****************************************************************************/ + static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class; static void @@ -392,13 +578,9 @@ _wireguard_peer_hash_update (const NMPWireGuardPeer *peer, peer->rx_bytes, peer->tx_bytes, peer->last_handshake_time.tv_sec, - peer->last_handshake_time.tv_nsec, - peer->endpoint.sa.sa_family); + peer->last_handshake_time.tv_nsec); - if (peer->endpoint.sa.sa_family == AF_INET) - nm_hash_update_val (h, peer->endpoint.in); - else if (peer->endpoint.sa.sa_family == AF_INET6) - nm_hash_update_val (h, peer->endpoint.in6); + nm_sock_addr_union_hash_update (&peer->endpoint, h); for (i = 0; i < peer->allowed_ips_len; i++) _wireguard_allowed_ip_hash_update (&peer->allowed_ips[i], h); @@ -422,10 +604,7 @@ _wireguard_peer_cmp (const NMPWireGuardPeer *a, NM_CMP_FIELD_MEMCMP (a, b, public_key); NM_CMP_FIELD_MEMCMP (a, b, preshared_key); - if (a->endpoint.sa.sa_family == AF_INET) - NM_CMP_FIELD_MEMCMP (a, b, endpoint.in); - else if (a->endpoint.sa.sa_family == AF_INET6) - NM_CMP_FIELD_MEMCMP (a, b, endpoint.in6); + NM_CMP_RETURN (nm_sock_addr_union_cmp (&a->endpoint, &b->endpoint)); for (i = 0; i < a->allowed_ips_len; i++) { NM_CMP_RETURN (_wireguard_allowed_ip_cmp (&a->allowed_ips[i], diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index e46b16c8f0..4649441bc5 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -37,6 +37,32 @@ typedef union { struct sockaddr_in6 in6; } NMSockAddrUnion; +#define NM_SOCK_ADDR_UNION_INIT_UNSPEC \ + { \ + .sa = { \ + .sa_family = AF_UNSPEC, \ + }, \ + } + +int nm_sock_addr_union_cmp (const NMSockAddrUnion *a, + const NMSockAddrUnion *b); + +void nm_sock_addr_union_hash_update (const NMSockAddrUnion *a, + NMHashState *h); + +void nm_sock_addr_union_cpy (NMSockAddrUnion *dst, + gconstpointer src /* unaligned (const NMSockAddrUnion *) */); + +void nm_sock_addr_union_cpy_untrusted (NMSockAddrUnion *dst, + gconstpointer src /* unaligned (const NMSockAddrUnion *) */, + gsize src_len); + +const char *nm_sock_addr_union_to_string (const NMSockAddrUnion *sa, + char *buf, + gsize len); + +/*****************************************************************************/ + typedef struct { NMIPAddr addr; guint8 family; diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 031bb79a25..bfd330580a 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -912,7 +912,8 @@ _test_wireguard_change (NMPlatform *platform, ifindex, &lnk_wireguard, (const NMPWireGuardPeer *) peers->data, - peers->len); + peers->len, + TRUE); g_assert (NMTST_NM_ERR_SUCCESS (r)); } |