libnm-util: convert from old IP6 address format to new

Ensure it still works correctly if something tries to set the
'addresses' property using the old GType.  Also make sure that
the various IP6 address comparison operations and string conversion
functions handle the gateway.
This commit is contained in:
Dan Williams 2010-04-19 10:14:44 -07:00
parent 73a7e6b8e0
commit 83652e6b8e
3 changed files with 182 additions and 5 deletions

View file

@ -19,7 +19,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 - 2008 Red Hat, Inc.
* (C) Copyright 2007 - 2010 Red Hat, Inc.
* (C) Copyright 2007 - 2008 Novell, Inc.
*/
@ -377,6 +377,7 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
GValue *tmp_val;
GByteArray *addr1, *addr2;
guint32 prefix1, prefix2;
GByteArray *gw1, *gw2;
gint ret = 0;
int i;
@ -387,8 +388,8 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
/* Since they are NM IPv6 address structures, we expect both
* to contain two elements as specified in nm-dbus-glib-types.h.
*/
g_return_val_if_fail (values1->n_values == 2, 0);
g_return_val_if_fail (values2->n_values == 2, 0);
g_return_val_if_fail (values1->n_values == 3, 0);
g_return_val_if_fail (values2->n_values == 3, 0);
/* First struct IPv6 address */
tmp_val = g_value_array_get_nth (values1, 0);
@ -396,6 +397,9 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
/* First struct IPv6 prefix */
tmp_val = g_value_array_get_nth (values1, 1);
prefix1 = g_value_get_uint (tmp_val);
/* First struct IPv6 gateway */
tmp_val = g_value_array_get_nth (values1, 2);
gw1 = g_value_get_boxed (tmp_val);
/* Second struct IPv6 address */
tmp_val = g_value_array_get_nth (values2, 0);
@ -403,6 +407,9 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
/* Second struct IPv6 prefix */
tmp_val = g_value_array_get_nth (values2, 1);
prefix2 = g_value_get_uint (tmp_val);
/* Second struct IPv6 gateway */
tmp_val = g_value_array_get_nth (values2, 2);
gw2 = g_value_get_boxed (tmp_val);
/* Compare IPv6 addresses */
if (prefix1 != prefix2)
@ -413,6 +420,11 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
ret = addr1->data[i] < addr2->data[i] ? -1 : addr1->data[i] > addr2->data[i];
}
if (!IN6_ARE_ADDR_EQUAL ((struct in6_addr *) gw1->data, (struct in6_addr *) gw2->data)) {
for (i = 0; ret == 0 && i < gw1->len; i++)
ret = gw1->data[i] < gw2->data[i] ? -1 : gw1->data[i] > gw2->data[i];
}
return ret;
}

View file

@ -275,6 +275,8 @@ nm_utils_init (GError **error)
if (!crypto_init (error))
return FALSE;
_nm_utils_register_value_transformations ();
atexit (nm_utils_deinit);
initialized = TRUE;
}
@ -886,6 +888,19 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu
continue;
}
g_string_append_printf (printable, "px = %u", prefix);
g_string_append (printable, ", ");
/* IPv6 Gateway */
tmp = g_value_array_get_nth (elements, 2);
ba_addr = g_value_get_boxed (tmp);
if (ba_addr->len != 16) {
g_string_append (printable, "invalid");
continue;
}
addr = (struct in6_addr *) ba_addr->data;
memset (buf, 0, sizeof (buf));
nm_utils_inet6_ntop (addr, buf);
g_string_append_printf (printable, "gw = %s", buf);
g_string_append (printable, " }");
}
g_string_append_c (printable, ']');
@ -977,6 +992,58 @@ nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GVal
g_string_free (printable, FALSE);
}
#define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
#define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS))
static void
nm_utils_convert_old_ip6_addr_array (const GValue *src_value, GValue *dst_value)
{
GPtrArray *src_outer_array;
GPtrArray *dst_outer_array;
guint i;
g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS));
src_outer_array = (GPtrArray *) g_value_get_boxed (src_value);
dst_outer_array = g_ptr_array_new ();
for (i = 0; src_outer_array && (i < src_outer_array->len); i++) {
GValueArray *src_addr_array;
GValueArray *dst_addr_array;
GValue element = {0, };
GValue *src_addr, *src_prefix;
GByteArray *ba;
src_addr_array = (GValueArray *) g_ptr_array_index (src_outer_array, i);
if ( (src_addr_array->n_values != 2)
|| (G_VALUE_TYPE (g_value_array_get_nth (src_addr_array, 0)) != DBUS_TYPE_G_UCHAR_ARRAY)
|| (G_VALUE_TYPE (g_value_array_get_nth (src_addr_array, 1)) != G_TYPE_UINT)) {
g_warning ("%s: invalid old IPv6 address type", __func__);
return;
}
dst_addr_array = g_value_array_new (3);
src_addr = g_value_array_get_nth (src_addr_array, 0);
g_value_array_append (dst_addr_array, src_addr);
src_prefix = g_value_array_get_nth (src_addr_array, 1);
g_value_array_append (dst_addr_array, src_prefix);
/* Blank Gateway */
g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
ba = g_byte_array_new ();
g_byte_array_append (ba, (guint8 *) "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16);
g_value_take_boxed (&element, ba);
g_value_array_append (dst_addr_array, &element);
g_value_unset (&element);
g_ptr_array_add (dst_outer_array, dst_addr_array);
}
g_value_take_boxed (dst_value, dst_outer_array);
}
void
_nm_utils_register_value_transformations (void)
{
@ -1013,6 +1080,9 @@ _nm_utils_register_value_transformations (void)
g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE,
G_TYPE_STRING,
nm_utils_convert_ip6_route_struct_array_to_string);
g_value_register_transform_func (OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
nm_utils_convert_old_ip6_addr_array);
registered = TRUE;
}
}

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2008 - 2009 Red Hat, Inc.
* Copyright (C) 2008 - 2010 Red Hat, Inc.
*
*/
@ -28,7 +28,8 @@
#include "nm-setting-connection.h"
#include "nm-setting-vpn.h"
#include "nm-setting-ip6-config.h"
#include "nm-dbus-glib-types.h"
static void
vpn_check_func (const char *key, const char *value, gpointer user_data)
@ -128,6 +129,99 @@ test_setting_vpn_items (void)
g_object_unref (s_vpn);
}
#define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
#define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS))
/* Test that setting the IPv6 setting's 'addresses' property using the old
* IPv6 address format still works, i.e. that the GValue transformation function
* from old->new is working correctly.
*/
static void
test_setting_ip6_config_old_address_array (void)
{
NMSettingIP6Config *s_ip6;
GPtrArray *addresses, *read_addresses;
GValueArray *array, *read_array;
GValue element = {0, }, written_value = {0, }, read_value = {0, };
GByteArray *ba;
const guint8 addr[16] = { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0x11, 0x22, 0x33, 0x44, 0x66, 0x77, 0x88, 0x99 };
const guint8 gw[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
guint32 prefix = 56;
GValue *read_addr, *read_prefix, *read_gw;
s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
ASSERT (s_ip6 != NULL,
"ip6-old-addr", "error creating IP6 setting");
g_value_init (&written_value, OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS);
addresses = g_ptr_array_new ();
array = g_value_array_new (3);
/* IP address */
g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
ba = g_byte_array_new ();
g_byte_array_append (ba, &addr[0], sizeof (addr));
g_value_take_boxed (&element, ba);
g_value_array_append (array, &element);
g_value_unset (&element);
/* Prefix */
g_value_init (&element, G_TYPE_UINT);
g_value_set_uint (&element, prefix);
g_value_array_append (array, &element);
g_value_unset (&element);
g_ptr_array_add (addresses, array);
g_value_set_boxed (&written_value, addresses);
/* Set the address array on the object */
g_object_set_property (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_ADDRESSES, &written_value);
/* Get it back so we can compare it */
g_value_init (&read_value, DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS);
g_object_get_property (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_ADDRESSES, &read_value);
ASSERT (G_VALUE_HOLDS (&read_value, DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS),
"ip6-old-addr", "wrong addresses property value type '%s'",
G_VALUE_TYPE_NAME (&read_value));
read_addresses = (GPtrArray *) g_value_get_boxed (&read_value);
ASSERT (read_addresses != NULL,
"ip6-old-addr", "missing addresses on readback");
ASSERT (read_addresses->len == 1,
"ip6-old-addr", "expected one address on readback");
read_array = (GValueArray *) g_ptr_array_index (read_addresses, 0);
read_addr = g_value_array_get_nth (read_array, 0);
ba = g_value_get_boxed (read_addr);
ASSERT (ba->len == sizeof (addr),
"ip6-old-addr", "unexpected address item length %d", ba->len);
ASSERT (memcmp (ba->data, &addr[0], sizeof (addr)) == 0,
"ip6-old-addr", "unexpected failure comparing addresses");
read_prefix = g_value_array_get_nth (read_array, 1);
ASSERT (g_value_get_uint (read_prefix) == prefix,
"ip6-old-addr", "unexpected failure comparing prefix");
/* Ensure the gateway is all zeros, which is how the 2-item to 3-item
* conversion happens.
*/
read_gw = g_value_array_get_nth (read_array, 2);
ba = g_value_get_boxed (read_gw);
ASSERT (ba->len == sizeof (gw),
"ip6-old-addr", "unexpected gateway item length %d", ba->len);
ASSERT (memcmp (ba->data, &gw[0], sizeof (gw)) == 0,
"ip6-old-addr", "unexpected failure comparing gateways");
g_value_unset (&written_value);
g_value_unset (&read_value);
g_object_unref (s_ip6);
}
int main (int argc, char **argv)
{
GError *error = NULL;
@ -142,6 +236,7 @@ int main (int argc, char **argv)
/* The tests */
test_setting_vpn_items ();
test_setting_ip6_config_old_address_array ();
base = g_path_get_basename (argv[0]);
fprintf (stdout, "%s: SUCCESS\n", base);