summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-01-22 16:31:22 +0100
committerThomas Haller <thaller@redhat.com>2019-01-22 16:31:59 +0100
commit81da34eb1e9e212653c7ab5a0505b455361369ee (patch)
tree6871dcfb92323a2c0d75a2032af18a89bde1a9f6
parentd7d2dafc1b25bc02a51c32e9660b66e4a987befe (diff)
parent69ce5def413b72c108fc11cdd9ffec53d74ea66e (diff)
downloadNetworkManager-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.c43
-rw-r--r--libnm-core/nm-setting-private.h7
-rw-r--r--libnm-core/nm-setting-vpn.c52
-rw-r--r--libnm-core/nm-setting.c312
-rw-r--r--libnm-core/nm-setting.h17
-rw-r--r--shared/nm-utils/nm-shared-utils.h10
-rw-r--r--shared/nm-utils/tests/test-shared-general.c53
-rw-r--r--src/platform/nm-linux-platform.c62
-rw-r--r--src/platform/nm-platform.c40
-rw-r--r--src/platform/nm-platform.h6
-rw-r--r--src/platform/nmp-object.c199
-rw-r--r--src/platform/nmp-object.h26
-rw-r--r--src/platform/tests/test-link.c3
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));
}