diff options
author | Dan Winship <danw@gnome.org> | 2014-10-20 21:30:56 -0400 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2014-11-07 07:49:40 -0500 |
commit | f17699f4e3dacb9358a8503c8b15efe3cb852b48 (patch) | |
tree | fc26094c54154b91497b4b5eac72eeca093fedf0 /libnm-core | |
parent | 329791ad55ee66e2d12c3cedcc2daf8c0865f7a6 (diff) | |
download | NetworkManager-f17699f4e3dacb9358a8503c8b15efe3cb852b48.tar.gz |
libnm-core: add NMSettingIPConfig:gateway, drop NMIPAddress:gateway
The gateway is a global property of the IPv4/IPv6 configuration, not
an attribute of any particular address. So represent it as such in the
API; remove the gateway from NMIPAddress, and add it to
NMSettingIPConfig.
Behind the scenes, the gateway is still serialized along with the
first address in NMSettingIPConfig:addresses, and is deserialized from
that if the settings dictionary doesn't contain a 'gateway' key.
Adjust nmcli's interactive mode to prompt for IP addresses and gateway
separately. (Patch partly from Jirka Klimeš.)
Diffstat (limited to 'libnm-core')
-rw-r--r-- | libnm-core/nm-setting-ip-config.c | 130 | ||||
-rw-r--r-- | libnm-core/nm-setting-ip-config.h | 8 | ||||
-rw-r--r-- | libnm-core/nm-setting-ip4-config.c | 23 | ||||
-rw-r--r-- | libnm-core/nm-setting-ip6-config.c | 57 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 83 | ||||
-rw-r--r-- | libnm-core/nm-utils.h | 12 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 152 |
7 files changed, 345 insertions, 120 deletions
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index ebe38712b2..0ed612cd06 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -102,7 +102,7 @@ G_DEFINE_BOXED_TYPE (NMIPAddress, nm_ip_address, nm_ip_address_dup, nm_ip_addres struct NMIPAddress { guint refcount; - char *address, *gateway; + char *address; int prefix, family; GHashTable *attributes; @@ -113,7 +113,6 @@ struct NMIPAddress { * @family: the IP address family (%AF_INET or %AF_INET6) * @addr: the IP address * @prefix: the address prefix length - * @gateway: (allow-none): the gateway * @error: location to store error, or %NULL * * Creates a new #NMIPAddress object. @@ -122,7 +121,7 @@ struct NMIPAddress { **/ NMIPAddress * nm_ip_address_new (int family, - const char *addr, guint prefix, const char *gateway, + const char *addr, guint prefix, GError **error) { NMIPAddress *address; @@ -134,8 +133,6 @@ nm_ip_address_new (int family, return NULL; if (!valid_prefix (family, prefix, error)) return NULL; - if (gateway && !valid_ip (family, gateway, error)) - return NULL; address = g_slice_new0 (NMIPAddress); address->refcount = 1; @@ -143,7 +140,6 @@ nm_ip_address_new (int family, address->family = family; address->address = canonicalize_ip (family, addr, FALSE); address->prefix = prefix; - address->gateway = canonicalize_ip (family, gateway, TRUE); return address; } @@ -153,17 +149,16 @@ nm_ip_address_new (int family, * @family: the IP address family (%AF_INET or %AF_INET6) * @addr: the IP address * @prefix: the address prefix length - * @gateway: (allow-none): the gateway * @error: location to store error, or %NULL * - * Creates a new #NMIPAddress object. @addr and @gateway (if non-%NULL) must - * point to buffers of the correct size for @family. + * Creates a new #NMIPAddress object. @addr must point to a buffer of the + * correct size for @family. * * Returns: (transfer full): the new #NMIPAddress object, or %NULL on error **/ NMIPAddress * nm_ip_address_new_binary (int family, - gconstpointer addr, guint prefix, gconstpointer gateway, + gconstpointer addr, guint prefix, GError **error) { NMIPAddress *address; @@ -181,8 +176,6 @@ nm_ip_address_new_binary (int family, address->family = family; address->address = g_strdup (inet_ntop (family, addr, string, sizeof (string))); address->prefix = prefix; - if (gateway) - address->gateway = g_strdup (inet_ntop (family, gateway, string, sizeof (string))); return address; } @@ -218,7 +211,6 @@ nm_ip_address_unref (NMIPAddress *address) address->refcount--; if (address->refcount == 0) { g_free (address->address); - g_free (address->gateway); if (address->attributes) g_hash_table_unref (address->attributes); g_slice_free (NMIPAddress, address); @@ -230,8 +222,8 @@ nm_ip_address_unref (NMIPAddress *address) * @address: the #NMIPAddress * @other: the #NMIPAddress to compare @address to. * - * Determines if two #NMIPAddress objects contain the same address, prefix, and - * gateway (attributes are not compared). + * Determines if two #NMIPAddress objects contain the same address and prefix + * (attributes are not compared). * * Returns: %TRUE if the objects contain the same values, %FALSE if they do not. **/ @@ -246,8 +238,7 @@ nm_ip_address_equal (NMIPAddress *address, NMIPAddress *other) if ( address->family != other->family || address->prefix != other->prefix - || strcmp (address->address, other->address) != 0 - || g_strcmp0 (address->gateway, other->gateway) != 0) + || strcmp (address->address, other->address) != 0) return FALSE; return TRUE; } @@ -269,7 +260,7 @@ nm_ip_address_dup (NMIPAddress *address) g_return_val_if_fail (address->refcount > 0, NULL); copy = nm_ip_address_new (address->family, - address->address, address->prefix, address->gateway, + address->address, address->prefix, NULL); if (address->attributes) { GHashTableIter iter; @@ -418,46 +409,6 @@ nm_ip_address_set_prefix (NMIPAddress *address, } /** - * nm_ip_address_get_gateway: - * @address: the #NMIPAddress - * - * Gets the gateway property of this address object; this will be %NULL if the - * address has no associated gateway. - * - * Returns: the gateway - **/ -const char * -nm_ip_address_get_gateway (NMIPAddress *address) -{ - g_return_val_if_fail (address != NULL, NULL); - g_return_val_if_fail (address->refcount > 0, NULL); - - return address->gateway; -} - -/** - * nm_ip_address_set_gateway: - * @address: the #NMIPAddress - * @gateway: (allow-none): the gateway, as a string - * - * Sets the gateway property of this address object. - * - * @gateway (if non-%NULL) must be a valid address of @address's family. If you - * aren't sure you have a valid address, use nm_utils_ipaddr_valid() to check - * it. - **/ -void -nm_ip_address_set_gateway (NMIPAddress *address, - const char *gateway) -{ - g_return_if_fail (address != NULL); - g_return_if_fail (!gateway || nm_utils_ipaddr_valid (address->family, gateway)); - - g_free (address->gateway); - address->gateway = canonicalize_ip (address->family, gateway, TRUE); -} - -/** * nm_ip_address_get_attribute_names: * @address: the #NMIPAddress * @@ -1081,6 +1032,7 @@ typedef struct { GPtrArray *dns_search; /* array of domain name strings */ GPtrArray *addresses; /* array of NMIPAddress */ GPtrArray *routes; /* array of NMIPRoute */ + char *gateway; gboolean ignore_auto_routes; gboolean ignore_auto_dns; char *dhcp_hostname; @@ -1095,6 +1047,7 @@ enum { PROP_DNS, PROP_DNS_SEARCH, PROP_ADDRESSES, + PROP_GATEWAY, PROP_ROUTES, PROP_IGNORE_AUTO_ROUTES, PROP_IGNORE_AUTO_DNS, @@ -1544,6 +1497,21 @@ nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting) } /** + * nm_setting_ip_config_get_gateway: + * @setting: the #NMSettingIPConfig + * + * Returns: the IP address of the gateway associated with this configuration, or + * %NULL. + **/ +const char * +nm_setting_ip_config_get_gateway (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->gateway; +} + +/** * nm_setting_ip_config_get_num_routes: * @setting: the #NMSettingIPConfig * @@ -1882,6 +1850,27 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } + /* Validate gateway */ + if (priv->gateway) { + if (!priv->addresses->len) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("gateway cannot be set if there are no addresses configured")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_GATEWAY); + return FALSE; + } + + if (!nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), priv->gateway)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("gateway is invalid")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_GATEWAY); + return FALSE; + } + } + /* Validate routes */ for (i = 0; i < priv->routes->len; i++) { NMIPRoute *route = (NMIPRoute *) priv->routes->pdata[i]; @@ -1919,6 +1908,7 @@ finalize (GObject *object) NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (self); g_free (priv->method); + g_free (priv->gateway); g_free (priv->dhcp_hostname); g_ptr_array_unref (priv->dns); @@ -1935,6 +1925,7 @@ set_property (GObject *object, guint prop_id, { NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object); NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + const char *gateway; switch (prop_id) { case PROP_METHOD: @@ -1955,6 +1946,12 @@ set_property (GObject *object, guint prop_id, (NMUtilsCopyFunc) nm_ip_address_dup, (GDestroyNotify) nm_ip_address_unref); break; + case PROP_GATEWAY: + gateway = g_value_get_string (value); + g_return_if_fail (!gateway || nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway)); + g_free (priv->gateway); + priv->gateway = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway, TRUE); + break; case PROP_ROUTES: g_ptr_array_unref (priv->routes); priv->routes = _nm_utils_copy_array (g_value_get_boxed (value), @@ -2008,6 +2005,9 @@ get_property (GObject *object, guint prop_id, (NMUtilsCopyFunc) nm_ip_address_dup, (GDestroyNotify) nm_ip_address_unref)); break; + case PROP_GATEWAY: + g_value_set_string (value, nm_setting_ip_config_get_gateway (setting)); + break; case PROP_ROUTES: g_value_take_boxed (value, _nm_utils_copy_array (priv->routes, (NMUtilsCopyFunc) nm_ip_route_dup, @@ -2119,6 +2119,20 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class) G_PARAM_STATIC_STRINGS)); /** + * NMSettingIPConfig:gateway: + * + * The gateway associated with this configuration. This is only meaningful + * if #NMSettingIPConfig:addresses is also set. + **/ + g_object_class_install_property + (object_class, PROP_GATEWAY, + g_param_spec_string (NM_SETTING_IP_CONFIG_GATEWAY, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** * NMSettingIPConfig:routes: * * Array of IP routes. diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index 0f2d16367c..37437761c4 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -38,12 +38,10 @@ GType nm_ip_address_get_type (void); NMIPAddress *nm_ip_address_new (int family, const char *addr, guint prefix, - const char *gateway, GError **error); NMIPAddress *nm_ip_address_new_binary (int family, gconstpointer addr, guint prefix, - gconstpointer gateway, GError **error); void nm_ip_address_ref (NMIPAddress *address); @@ -63,9 +61,6 @@ void nm_ip_address_set_address_binary (NMIPAddress *address, guint nm_ip_address_get_prefix (NMIPAddress *address); void nm_ip_address_set_prefix (NMIPAddress *address, guint prefix); -const char *nm_ip_address_get_gateway (NMIPAddress *address); -void nm_ip_address_set_gateway (NMIPAddress *address, - const char *gateway); char **nm_ip_address_get_attribute_names (NMIPAddress *address); GVariant *nm_ip_address_get_attribute (NMIPAddress *address, @@ -139,6 +134,7 @@ void nm_ip_route_set_attribute (NMIPRoute *route, #define NM_SETTING_IP_CONFIG_DNS "dns" #define NM_SETTING_IP_CONFIG_DNS_SEARCH "dns-search" #define NM_SETTING_IP_CONFIG_ADDRESSES "addresses" +#define NM_SETTING_IP_CONFIG_GATEWAY "gateway" #define NM_SETTING_IP_CONFIG_ROUTES "routes" #define NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES "ignore-auto-routes" #define NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS "ignore-auto-dns" @@ -195,6 +191,8 @@ gboolean nm_setting_ip_config_remove_address_by_value (NMSettingIPConfig NMIPAddress *address); void nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting); +const char *nm_setting_ip_config_get_gateway (NMSettingIPConfig *setting); + guint nm_setting_ip_config_get_num_routes (NMSettingIPConfig *setting); NMIPRoute *nm_setting_ip_config_get_route (NMSettingIPConfig *setting, int i); diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c index 068ba0451a..66f2ea997e 100644 --- a/libnm-core/nm-setting-ip4-config.c +++ b/libnm-core/nm-setting-ip4-config.c @@ -102,10 +102,12 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting); NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); + NMSettingVerifyResult ret; const char *method; - if (!NM_SETTING_CLASS (nm_setting_ip4_config_parent_class)->verify (setting, connection, error)) - return FALSE; + ret = NM_SETTING_CLASS (nm_setting_ip4_config_parent_class)->verify (setting, connection, error); + if (ret != NM_SETTING_VERIFY_SUCCESS) + return ret; method = nm_setting_ip_config_get_method (s_ip); /* Base class already checked that it exists */ @@ -245,10 +247,12 @@ ip4_addresses_get (NMSetting *setting, const char *property) { GPtrArray *addrs; + const char *gateway; GVariant *ret; g_object_get (setting, property, &addrs, NULL); - ret = nm_utils_ip4_addresses_to_variant (addrs); + gateway = nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (setting)); + ret = nm_utils_ip4_addresses_to_variant (addrs, gateway); g_ptr_array_unref (addrs); return ret; @@ -262,18 +266,27 @@ ip4_addresses_set (NMSetting *setting, { GPtrArray *addrs; GVariant *s_ip4; - char **labels; + char **labels, *gateway = NULL; int i; - addrs = nm_utils_ip4_addresses_from_variant (value); + addrs = nm_utils_ip4_addresses_from_variant (value, &gateway); 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", "^as", &labels)) { for (i = 0; i < addrs->len && labels[i]; i++) if (*labels[i]) nm_ip_address_set_attribute (addrs->pdata[i], "label", g_variant_new_string (labels[i])); g_strfreev (labels); } + + if (gateway && !g_variant_lookup (s_ip4, "gateway", "s", NULL)) { + g_object_set (setting, + NM_SETTING_IP_CONFIG_GATEWAY, gateway, + NULL); + } + g_free (gateway); + g_variant_unref (s_ip4); g_object_set (setting, property, addrs, NULL); diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index dc05e541c3..9e3001157e 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -100,10 +100,12 @@ static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); + NMSettingVerifyResult ret; const char *method; - if (!NM_SETTING_CLASS (nm_setting_ip6_config_parent_class)->verify (setting, connection, error)) - return FALSE; + ret = NM_SETTING_CLASS (nm_setting_ip6_config_parent_class)->verify (setting, connection, error); + if (ret != NM_SETTING_VERIFY_SUCCESS) + return ret; method = nm_setting_ip_config_get_method (s_ip); /* Base class already checked that it exists */ @@ -187,16 +189,46 @@ ip6_dns_from_dbus (GVariant *dbus_value, } static GVariant * -ip6_addresses_to_dbus (const GValue *prop_value) +ip6_addresses_get (NMSetting *setting, + const char *property) { - return nm_utils_ip6_addresses_to_variant (g_value_get_boxed (prop_value)); + GPtrArray *addrs; + const char *gateway; + GVariant *ret; + + g_object_get (setting, property, &addrs, NULL); + gateway = nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (setting)); + ret = nm_utils_ip6_addresses_to_variant (addrs, gateway); + g_ptr_array_unref (addrs); + + return ret; } static void -ip6_addresses_from_dbus (GVariant *dbus_value, - GValue *prop_value) +ip6_addresses_set (NMSetting *setting, + GVariant *connection_dict, + const char *property, + GVariant *value) { - g_value_take_boxed (prop_value, nm_utils_ip6_addresses_from_variant (dbus_value)); + GPtrArray *addrs; + GVariant *s_ip6; + char *gateway = NULL; + + addrs = nm_utils_ip6_addresses_from_variant (value, &gateway); + + s_ip6 = g_variant_lookup_value (connection_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING); + + if (gateway && !g_variant_lookup (s_ip6, "gateway", "s", NULL)) { + g_object_set (setting, + NM_SETTING_IP_CONFIG_GATEWAY, gateway, + NULL); + } + g_free (gateway); + + g_variant_unref (s_ip6); + + g_object_set (setting, property, addrs, NULL); + g_ptr_array_unref (addrs); } static GVariant * @@ -285,11 +317,12 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class) ip6_dns_to_dbus, ip6_dns_from_dbus); - _nm_setting_class_transform_property (setting_class, - NM_SETTING_IP_CONFIG_ADDRESSES, - G_VARIANT_TYPE ("a(ayuay)"), - ip6_addresses_to_dbus, - ip6_addresses_from_dbus); + _nm_setting_class_override_property (setting_class, + NM_SETTING_IP_CONFIG_ADDRESSES, + G_VARIANT_TYPE ("a(ayuay)"), + ip6_addresses_get, + ip6_addresses_set, + NULL); _nm_setting_class_transform_property (setting_class, NM_SETTING_IP_CONFIG_ROUTES, diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 110142fbfc..62698eefc8 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -1136,16 +1136,18 @@ nm_utils_ip4_dns_from_variant (GVariant *value) /** * nm_utils_ip4_addresses_to_variant: * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects + * @gateway: (allow-none): the gateway IP address * * Utility function to convert a #GPtrArray of #NMIPAddress objects representing * IPv4 addresses into a #GVariant of type 'aau' representing an array of * NetworkManager IPv4 addresses (which are tuples of address, prefix, and - * gateway, although only the first "gateway" field is preserved) + * gateway). The "gateway" field of the first address will get the value of + * @gateway (if non-%NULL). In all of the other addresses, that field will be 0. * * Returns: (transfer none): a new floating #GVariant representing @addresses. **/ GVariant * -nm_utils_ip4_addresses_to_variant (GPtrArray *addresses) +nm_utils_ip4_addresses_to_variant (GPtrArray *addresses, const char *gateway) { GVariantBuilder builder; int i; @@ -1162,8 +1164,8 @@ nm_utils_ip4_addresses_to_variant (GPtrArray *addresses) nm_ip_address_get_address_binary (addr, &array[0]); array[1] = nm_ip_address_get_prefix (addr); - if (i == 0 && nm_ip_address_get_gateway (addr)) - inet_pton (AF_INET, nm_ip_address_get_gateway (addr), &array[2]); + if (i == 0 && gateway) + inet_pton (AF_INET, gateway, &array[2]); else array[2] = 0; @@ -1179,17 +1181,19 @@ nm_utils_ip4_addresses_to_variant (GPtrArray *addresses) /** * nm_utils_ip4_addresses_from_variant: * @value: a #GVariant of type 'aau' + * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway * * Utility function to convert a #GVariant of type 'aau' representing a list of * NetworkManager IPv4 addresses (which are tuples of address, prefix, and - * gateway, although only the first "gateway" field is preserved) into a - * #GPtrArray of #NMIPAddress objects. + * gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field of + * the first address (if set) will be returned in @out_gateway; the "gateway" fields + * of the other addresses are ignored. * * Returns: (transfer full) (element-type NMIPAddress): a newly allocated * #GPtrArray of #NMIPAddress objects **/ GPtrArray * -nm_utils_ip4_addresses_from_variant (GVariant *value) +nm_utils_ip4_addresses_from_variant (GVariant *value, char **out_gateway) { GPtrArray *addresses; GVariantIter iter; @@ -1197,6 +1201,9 @@ nm_utils_ip4_addresses_from_variant (GVariant *value) g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL); + if (out_gateway) + *out_gateway = NULL; + g_variant_iter_init (&iter, value); addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref); @@ -1213,16 +1220,19 @@ nm_utils_ip4_addresses_from_variant (GVariant *value) continue; } - addr = nm_ip_address_new_binary (AF_INET, - &addr_array[0], addr_array[1], - addresses->len == 0 ? &addr_array[2] : NULL, - &error); + addr = nm_ip_address_new_binary (AF_INET, &addr_array[0], addr_array[1], &error); + if (addresses->len == 0 && out_gateway) { + if (addr_array[2]) + *out_gateway = g_strdup (nm_utils_inet4_ntop (addr_array[2], NULL)); + } + if (addr) g_ptr_array_add (addresses, addr); else { g_warning ("Ignoring invalid IP4 address: %s", error->message); g_clear_error (&error); } + g_variant_unref (addr_var); } @@ -1469,16 +1479,19 @@ nm_utils_ip6_dns_from_variant (GVariant *value) /** * nm_utils_ip6_addresses_to_variant: * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects + * @gateway: (allow-none): the gateway IP address * * Utility function to convert a #GPtrArray of #NMIPAddress objects representing * IPv6 addresses into a #GVariant of type 'a(ayuay)' representing an array of * NetworkManager IPv6 addresses (which are tuples of address, prefix, and - * gateway, although only the first "gateway" field is preserved). + * gateway). The "gateway" field of the first address will get the value of + * @gateway (if non-%NULL). In all of the other addresses, that field will be + * all 0s. * * Returns: (transfer none): a new floating #GVariant representing @addresses. **/ GVariant * -nm_utils_ip6_addresses_to_variant (GPtrArray *addresses) +nm_utils_ip6_addresses_to_variant (GPtrArray *addresses, const char *gateway) { GVariantBuilder builder; int i; @@ -1489,24 +1502,24 @@ nm_utils_ip6_addresses_to_variant (GPtrArray *addresses) for (i = 0; i < addresses->len; i++) { NMIPAddress *addr = addresses->pdata[i]; struct in6_addr ip_bytes, gateway_bytes; - GVariant *ip, *gateway; + GVariant *ip_var, *gateway_var; guint32 prefix; if (nm_ip_address_get_family (addr) != AF_INET6) continue; nm_ip_address_get_address_binary (addr, &ip_bytes); - ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &ip_bytes, 16, 1); + ip_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &ip_bytes, 16, 1); prefix = nm_ip_address_get_prefix (addr); - - if (i == 0 && nm_ip_address_get_gateway (addr)) - inet_pton (AF_INET6, nm_ip_address_get_gateway (addr), &gateway_bytes); + + if (i == 0 && gateway) + inet_pton (AF_INET6, gateway, &gateway_bytes); else memset (&gateway_bytes, 0, sizeof (gateway_bytes)); - gateway = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1); + gateway_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1); - g_variant_builder_add (&builder, "(@ayu@ay)", ip, prefix, gateway); + g_variant_builder_add (&builder, "(@ayu@ay)", ip_var, prefix, gateway_var); } } @@ -1516,17 +1529,19 @@ nm_utils_ip6_addresses_to_variant (GPtrArray *addresses) /** * nm_utils_ip6_addresses_from_variant: * @value: a #GVariant of type 'a(ayuay)' + * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway * * Utility function to convert a #GVariant of type 'a(ayuay)' representing a * list of NetworkManager IPv6 addresses (which are tuples of address, prefix, - * and gateway, although only the first "gateway" field is preserved) into a - * #GPtrArray of #NMIPAddress objects. + * and gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field + * of the first address (if set) will be returned in @out_gateway; the "gateway" + * fields of the other addresses are ignored. * * Returns: (transfer full) (element-type NMIPAddress): a newly allocated * #GPtrArray of #NMIPAddress objects **/ GPtrArray * -nm_utils_ip6_addresses_from_variant (GVariant *value) +nm_utils_ip6_addresses_from_variant (GVariant *value, char **out_gateway) { GVariantIter iter; GVariant *addr_var, *gateway_var; @@ -1535,6 +1550,9 @@ nm_utils_ip6_addresses_from_variant (GVariant *value) g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuay)")), NULL); + if (out_gateway) + *out_gateway = NULL; + g_variant_iter_init (&iter, value); addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref); @@ -1556,16 +1574,19 @@ nm_utils_ip6_addresses_from_variant (GVariant *value) __func__, (int) addr_len); goto next; } - gateway_bytes = g_variant_get_fixed_array (gateway_var, &gateway_len, 1); - if (gateway_len != 16) { - g_warning ("%s: ignoring invalid IP6 address of length %d", - __func__, (int) gateway_len); - goto next; + + if (addresses->len == 0 && out_gateway) { + gateway_bytes = g_variant_get_fixed_array (gateway_var, &gateway_len, 1); + if (gateway_len != 16) { + g_warning ("%s: ignoring invalid IP6 address of length %d", + __func__, (int) gateway_len); + goto next; + } + if (!IN6_IS_ADDR_UNSPECIFIED (gateway_bytes)) + *out_gateway = g_strdup (nm_utils_inet6_ntop (gateway_bytes, NULL)); } - addr = nm_ip_address_new_binary (AF_INET6, addr_bytes, prefix, - addresses->len == 0 ? gateway_bytes : NULL, - &error); + addr = nm_ip_address_new_binary (AF_INET6, addr_bytes, prefix, &error); if (addr) g_ptr_array_add (addresses, addr); else { diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index ccf15f7b84..628fa0f5a6 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -97,8 +97,10 @@ gboolean nm_utils_wpa_psk_valid (const char *psk); GVariant *nm_utils_ip4_dns_to_variant (char **dns); char **nm_utils_ip4_dns_from_variant (GVariant *value); -GVariant *nm_utils_ip4_addresses_to_variant (GPtrArray *addresses); -GPtrArray *nm_utils_ip4_addresses_from_variant (GVariant *value); +GVariant *nm_utils_ip4_addresses_to_variant (GPtrArray *addresses, + const char *gateway); +GPtrArray *nm_utils_ip4_addresses_from_variant (GVariant *value, + char **out_gateway); GVariant *nm_utils_ip4_routes_to_variant (GPtrArray *routes); GPtrArray *nm_utils_ip4_routes_from_variant (GVariant *value); @@ -108,8 +110,10 @@ guint32 nm_utils_ip4_get_default_prefix (guint32 ip); GVariant *nm_utils_ip6_dns_to_variant (char **dns); char **nm_utils_ip6_dns_from_variant (GVariant *value); -GVariant *nm_utils_ip6_addresses_to_variant (GPtrArray *addresses); -GPtrArray *nm_utils_ip6_addresses_from_variant (GVariant *value); +GVariant *nm_utils_ip6_addresses_to_variant (GPtrArray *addresses, + const char *gateway); +GPtrArray *nm_utils_ip6_addresses_from_variant (GVariant *value, + char **out_gateway); GVariant *nm_utils_ip6_routes_to_variant (GPtrArray *routes); GPtrArray *nm_utils_ip6_routes_from_variant (GVariant *value); diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 041c4263f4..d66a9c9f6e 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -338,7 +338,7 @@ test_setting_ip4_config_labels (void) NULL); /* addr 1 */ - addr = nm_ip_address_new (AF_INET, "1.1.1.1", 24, NULL, &error); + addr = nm_ip_address_new (AF_INET, "1.1.1.1", 24, &error); g_assert_no_error (error); nm_setting_ip_config_add_address (s_ip4, addr); @@ -351,7 +351,7 @@ test_setting_ip4_config_labels (void) g_assert (label == NULL); /* addr 2 */ - addr = nm_ip_address_new (AF_INET, "2.2.2.2", 24, NULL, &error); + addr = nm_ip_address_new (AF_INET, "2.2.2.2", 24, &error); g_assert_no_error (error); nm_ip_address_set_attribute (addr, "label", g_variant_new_string ("eth0:1")); @@ -366,7 +366,7 @@ test_setting_ip4_config_labels (void) g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1"); /* addr 3 */ - addr = nm_ip_address_new (AF_INET, "3.3.3.3", 24, NULL, &error); + addr = nm_ip_address_new (AF_INET, "3.3.3.3", 24, &error); g_assert_no_error (error); nm_ip_address_set_attribute (addr, "label", NULL); @@ -1634,6 +1634,7 @@ test_connection_diff_a_only (void) { NM_SETTING_IP_CONFIG_DNS, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP_CONFIG_DNS_SEARCH, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_DIFF_RESULT_IN_A }, + { NM_SETTING_IP_CONFIG_GATEWAY, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP_CONFIG_ROUTES, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, NM_SETTING_DIFF_RESULT_IN_A }, @@ -2480,7 +2481,7 @@ test_setting_ip4_changed_signal (void) ASSERT_CHANGED (nm_setting_ip_config_add_dns_search (s_ip4, "foobar.com")); ASSERT_CHANGED (nm_setting_ip_config_clear_dns_searches (s_ip4)); - addr = nm_ip_address_new (AF_INET, "22.33.0.0", 24, NULL, &error); + addr = nm_ip_address_new (AF_INET, "22.33.0.0", 24, &error); g_assert_no_error (error); ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip4, addr)); ASSERT_CHANGED (nm_setting_ip_config_remove_address (s_ip4, 0)); @@ -2549,7 +2550,7 @@ test_setting_ip6_changed_signal (void) nm_setting_ip_config_add_dns_search (s_ip6, "foobar.com"); ASSERT_CHANGED (nm_setting_ip_config_clear_dns_searches (s_ip6)); - addr = nm_ip_address_new (AF_INET6, "1:2:3::4:5:6", 64, NULL, &error); + addr = nm_ip_address_new (AF_INET6, "1:2:3::4:5:6", 64, &error); g_assert_no_error (error); ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip6, addr)); @@ -3336,6 +3337,145 @@ test_connection_normalize_infiniband_mtu (void) g_assert_cmpint (65520, ==, nm_setting_infiniband_get_mtu (s_infini)); } +static void +test_setting_ip4_gateway (void) +{ + NMConnection *conn; + NMSettingIPConfig *s_ip4; + NMIPAddress *addr; + GVariant *conn_dict, *ip4_dict, *value; + GVariantIter iter; + GVariant *addr_var; + GError *error = NULL; + + /* When serializing, ipv4.gateway is copied to the first entry of ipv4.addresses */ + conn = nmtst_create_minimal_connection ("test_setting_ip4_gateway", NULL, + NM_SETTING_WIRED_SETTING_NAME, NULL); + s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_GATEWAY, "192.168.1.1", + NULL); + nm_connection_add_setting (conn, NM_SETTING (s_ip4)); + + addr = nm_ip_address_new (AF_INET, "192.168.1.10", 24, &error); + g_assert_no_error (error); + nm_setting_ip_config_add_address (s_ip4, addr); + nm_ip_address_unref (addr); + + conn_dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL); + g_object_unref (conn); + + ip4_dict = g_variant_lookup_value (conn_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING); + g_assert (ip4_dict != NULL); + + value = g_variant_lookup_value (ip4_dict, NM_SETTING_IP_CONFIG_GATEWAY, G_VARIANT_TYPE_STRING); + g_assert (value != NULL); + g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "192.168.1.1"); + g_variant_unref (value); + + value = g_variant_lookup_value (ip4_dict, NM_SETTING_IP_CONFIG_ADDRESSES, G_VARIANT_TYPE ("aau")); + g_assert (value != NULL); + + g_variant_iter_init (&iter, value); + while (g_variant_iter_next (&iter, "@au", &addr_var)) { + const guint32 *addr_array; + gsize length; + + addr_array = g_variant_get_fixed_array (addr_var, &length, sizeof (guint32)); + g_assert_cmpint (length, ==, 3); + g_assert_cmpstr (nm_utils_inet4_ntop (addr_array[2], NULL), ==, "192.168.1.1"); + g_variant_unref (addr_var); + } + g_variant_unref (value); + + g_variant_unref (ip4_dict); + + /* When deserializing, the first gateway in ipv4.addresses is copied to ipv4.gateway */ + NMTST_VARIANT_EDITOR (conn_dict, + NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_GATEWAY); + ); + + conn = nm_simple_connection_new_from_dbus (conn_dict, &error); + g_variant_unref (conn_dict); + g_assert_no_error (error); + + s_ip4 = (NMSettingIPConfig *) nm_connection_get_setting_ip4_config (conn); + g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1"); + + g_object_unref (conn); +} + +static void +test_setting_ip6_gateway (void) +{ + NMConnection *conn; + NMSettingIPConfig *s_ip6; + NMIPAddress *addr; + GVariant *conn_dict, *ip6_dict, *value; + GVariantIter iter; + GVariant *gateway_var; + GError *error = NULL; + + /* When serializing, ipv6.gateway is copied to the first entry of ipv6.addresses */ + conn = nmtst_create_minimal_connection ("test_setting_ip6_gateway", NULL, + NM_SETTING_WIRED_SETTING_NAME, NULL); + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_GATEWAY, "abcd::1", + NULL); + nm_connection_add_setting (conn, NM_SETTING (s_ip6)); + + addr = nm_ip_address_new (AF_INET6, "abcd::10", 64, &error); + g_assert_no_error (error); + nm_setting_ip_config_add_address (s_ip6, addr); + nm_ip_address_unref (addr); + + conn_dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL); + g_object_unref (conn); + + ip6_dict = g_variant_lookup_value (conn_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING); + g_assert (ip6_dict != NULL); + + value = g_variant_lookup_value (ip6_dict, NM_SETTING_IP_CONFIG_GATEWAY, G_VARIANT_TYPE_STRING); + g_assert (value != NULL); + g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "abcd::1"); + + value = g_variant_lookup_value (ip6_dict, NM_SETTING_IP_CONFIG_ADDRESSES, G_VARIANT_TYPE ("a(ayuay)")); + g_assert (value != NULL); + + g_variant_iter_init (&iter, value); + while (g_variant_iter_next (&iter, "(@ayu@ay)", NULL, NULL, &gateway_var)) { + const guint8 *gateway_bytes; + gsize length; + + gateway_bytes = g_variant_get_fixed_array (gateway_var, &length, 1); + g_assert_cmpint (length, ==, 16); + g_assert_cmpstr (nm_utils_inet6_ntop ((struct in6_addr *) gateway_bytes, NULL), ==, "abcd::1"); + g_variant_unref (gateway_var); + } + g_variant_unref (value); + + g_variant_unref (ip6_dict); + + /* When deserializing, the first gateway in ipv4.addresses is copied to ipv4.gateway */ + NMTST_VARIANT_EDITOR (conn_dict, + NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_GATEWAY); + ); + + conn = nm_simple_connection_new_from_dbus (conn_dict, &error); + g_variant_unref (conn_dict); + g_assert_no_error (error); + + s_ip6 = (NMSettingIPConfig *) nm_connection_get_setting_ip6_config (conn); + g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip6), ==, "abcd::1"); + + g_object_unref (conn); +} + NMTST_DEFINE (); int main (int argc, char **argv) @@ -3424,6 +3564,8 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_setting_wireless_changed_signal", test_setting_wireless_changed_signal); g_test_add_func ("/core/general/test_setting_wireless_security_changed_signal", test_setting_wireless_security_changed_signal); g_test_add_func ("/core/general/test_setting_802_1x_changed_signal", test_setting_802_1x_changed_signal); + g_test_add_func ("/core/general/test_setting_ip4_gateway", test_setting_ip4_gateway); + g_test_add_func ("/core/general/test_setting_ip6_gateway", test_setting_ip6_gateway); return g_test_run (); } |