diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c index 9bc6b1b081..09ce3a25df 100644 --- a/src/libnm-core-impl/nm-setting-ip4-config.c +++ b/src/libnm-core-impl/nm-setting-ip4-config.c @@ -425,32 +425,24 @@ ip4_addresses_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil) { gs_unref_ptrarray GPtrArray *addrs = NULL; gs_unref_variant GVariant *s_ip4 = NULL; - gs_free const char **labels = NULL; + gs_unref_variant GVariant *labels = NULL; gs_free char *gateway = NULL; bool strict = NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT); - guint i; if (!_nm_setting_use_legacy_property(setting, connection_dict, "addresses", "address-data")) { *out_is_modified = FALSE; return TRUE; } - addrs = _nm_utils_ip4_addresses_from_variant(value, &gateway, strict, error); - if (!addrs) - return FALSE; - s_ip4 = g_variant_lookup_value(connection_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING); - if (g_variant_lookup(s_ip4, "address-labels", "^a&s", &labels)) { - for (i = 0; i < addrs->len && labels[i]; i++) { - if (*labels[i]) { - nm_ip_address_set_attribute(addrs->pdata[i], - NM_IP_ADDRESS_ATTRIBUTE_LABEL, - g_variant_new_string(labels[i])); - } - } - } + + labels = g_variant_lookup_value(s_ip4, "address-labels", NULL); + + addrs = _nm_utils_ip4_addresses_from_variant(value, labels, &gateway, strict, error); + if (!addrs) + return FALSE; g_object_set(setting, NM_SETTING_IP_CONFIG_ADDRESSES, diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c index 1f206337ab..ae8bc84194 100644 --- a/src/libnm-core-impl/nm-utils.c +++ b/src/libnm-core-impl/nm-utils.c @@ -1446,25 +1446,37 @@ nm_utils_ip4_addresses_to_variant(GPtrArray *addresses, const char *gateway) GPtrArray * nm_utils_ip4_addresses_from_variant(GVariant *value, char **out_gateway) { - return _nm_utils_ip4_addresses_from_variant(value, out_gateway, FALSE, NULL); + return _nm_utils_ip4_addresses_from_variant(value, NULL, out_gateway, FALSE, NULL); } /** * _nm_utils_ip4_addresses_from_variant: * @value: a #GVariant of type 'aau' + * @labels: (optional) (nullable): a #GVariant of the type 'as'. If not-NULL, + * each element must contain a string with the labels that corresponds to each + * IP address in @value. * @out_gateway: (out) (optional) (nullable) (transfer full): on return, will * contain the IP gateway * @strict: whether to parse in strict mode or best-effort mode * @error: the error location * * Like #nm_utils_ip4_addresses_from_variant, but allows to parse in strict mode. In - * strict mode, parsing is aborted on first error and %NULL is returned. + * strict mode, parsing is aborted on first error and %NULL is returned. It also + * allows to parse the address-labels at the same time than the addresses. + * + * The labels need to be processed at the same time than the addresses, inside + * this function, because if there are invalid addresses they are filtered out, + * and the returned array of addresses contains less elements than the original + * array. If that happens, the caller don't know what label corresponds to what + * address, because they are matched by position in the array. If you are not + * interested in the labels, just set @labels to NULL. * * Returns: (transfer full) (element-type NMIPAddress): a newly allocated * #GPtrArray of #NMIPAddress objects. In strict mode, %NULL is returned on error. */ GPtrArray * _nm_utils_ip4_addresses_from_variant(GVariant *value, + GVariant *labels, char **out_gateway, bool strict, GError **error) @@ -1475,6 +1487,8 @@ _nm_utils_ip4_addresses_from_variant(GVariant *value, const guint32 *addr_array; gsize length; NMIPAddress *addr; + const char *label; + gsize n_labels = 0; guint i; addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref); @@ -1492,6 +1506,21 @@ _nm_utils_ip4_addresses_from_variant(GVariant *value, return g_steal_pointer(&addresses); } + if (labels && !g_variant_is_of_type(labels, G_VARIANT_TYPE("as"))) { + if (strict) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Expected \"address-labels\" of type \"as\"")); + return NULL; + } + /* We still can parse the addresses, without the labels */ + labels = NULL; + } + + if (labels) + n_labels = g_variant_n_children(labels); + g_variant_iter_init(&iter, value); for (i = 0; g_variant_iter_next(&iter, "@au", &item); i++) { @@ -1525,6 +1554,18 @@ _nm_utils_ip4_addresses_from_variant(GVariant *value, continue; } + /* We were accepting address-labels to be shorter than addresses, so + * let's continue doing so and not consider it as an error */ + if (labels && i < n_labels) { + g_variant_get_child(labels, i, "&s", &label); + + if (label && label[0]) { + nm_ip_address_set_attribute(addr, + NM_IP_ADDRESS_ATTRIBUTE_LABEL, + g_variant_new_string(label)); + } + } + g_ptr_array_add(addresses, addr); if (addr_array[2] && out_gateway && !*out_gateway) *out_gateway = nm_inet4_ntop_dup(addr_array[2]); diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 2b486f8b88..16b03bc4dd 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -1086,6 +1086,7 @@ char **_nm_utils_ip4_dns_from_variant(GVariant *value, bool strict, GError **err GPtrArray *_nm_utils_ip4_routes_from_variant(GVariant *value, bool strict, GError **error); GPtrArray *_nm_utils_ip4_addresses_from_variant(GVariant *value, + GVariant *labels, char **out_gateway, bool strict, GError **error);