From a74e2cfde052120753bd2050fb9a7a1dc79e8a8f Mon Sep 17 00:00:00 2001 From: Jirka Klimes Date: Fri, 8 Jan 2010 11:23:39 -0800 Subject: [PATCH] keyfile: add IPv6 support (bgo #593814) (fixes by dcbw to use '/' as the prefix separator) --- system-settings/plugins/keyfile/io/reader.c | 333 +++++++++++++++++- system-settings/plugins/keyfile/io/writer.c | 200 ++++++++++- .../tests/keyfiles/Test_Wired_Connection | 10 + .../plugins/keyfile/tests/test-keyfile.c | 280 ++++++++++++++- 4 files changed, 803 insertions(+), 20 deletions(-) diff --git a/system-settings/plugins/keyfile/io/reader.c b/system-settings/plugins/keyfile/io/reader.c index 13c4b12703..3a4ec42e84 100644 --- a/system-settings/plugins/keyfile/io/reader.c +++ b/system-settings/plugins/keyfile/io/reader.c @@ -15,8 +15,8 @@ * 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 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2009 Novell, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. */ #include @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,7 @@ get_one_int (const char *str, guint32 max_val, const char *key_name, guint32 *ou errno = 0; tmp = strtol (str, NULL, 10); if (errno || (tmp < 0) || (tmp > max_val)) { - g_warning ("%s: ignoring invalid IPv4 %s item '%s'", __func__, key_name, str); + g_warning ("%s: ignoring invalid IP %s item '%s'", __func__, key_name, str); return FALSE; } @@ -78,13 +79,13 @@ get_one_int (const char *str, guint32 max_val, const char *key_name, guint32 *ou } static void -free_one_address (gpointer data, gpointer user_data) +free_one_ip4_address (gpointer data, gpointer user_data) { g_array_free ((GArray *) data, TRUE); } static GPtrArray * -read_addresses (GKeyFile *file, +read_ip4_addresses (GKeyFile *file, const char *setting_name, const char *key) { @@ -166,27 +167,27 @@ ip4_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) GPtrArray *addresses; const char *setting_name = nm_setting_get_name (setting); - addresses = read_addresses (keyfile, setting_name, key); + addresses = read_ip4_addresses (keyfile, setting_name, key); /* Work around for previous syntax */ if (!addresses && !strcmp (key, NM_SETTING_IP4_CONFIG_ADDRESSES)) - addresses = read_addresses (keyfile, setting_name, "address"); + addresses = read_ip4_addresses (keyfile, setting_name, "address"); if (addresses) { g_object_set (setting, key, addresses, NULL); - g_ptr_array_foreach (addresses, free_one_address, NULL); + g_ptr_array_foreach (addresses, free_one_ip4_address, NULL); g_ptr_array_free (addresses, TRUE); } } static void -free_one_route (gpointer data, gpointer user_data) +free_one_ip4_route (gpointer data, gpointer user_data) { g_array_free ((GArray *) data, TRUE); } static GPtrArray * -read_routes (GKeyFile *file, +read_ip4_routes (GKeyFile *file, const char *setting_name, const char *key) { @@ -272,10 +273,10 @@ ip4_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) GPtrArray *routes; const char *setting_name = nm_setting_get_name (setting); - routes = read_routes (keyfile, setting_name, key); + routes = read_ip4_routes (keyfile, setting_name, key); if (routes) { g_object_set (setting, key, routes, NULL); - g_ptr_array_foreach (routes, free_one_route, NULL); + g_ptr_array_foreach (routes, free_one_ip4_route, NULL); g_ptr_array_free (routes, TRUE); } } @@ -303,8 +304,9 @@ ip4_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) continue; } - g_array_append_val (array, addr.s_addr); + g_array_append_val (array, addr.s_addr); } + g_strfreev (list); if (array) { g_object_set (setting, key, array, NULL); @@ -312,6 +314,294 @@ ip4_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) } } +static void +free_one_ip6_address (gpointer data, gpointer user_data) +{ + g_value_array_free ((GValueArray *) data); +} + +static char * +split_prefix (char *addr) +{ + char *slash; + + g_return_val_if_fail (addr != NULL, NULL); + + /* Find the prefix and split the string */ + slash = strchr (addr, '/'); + if (slash && slash > addr) { + slash++; + *(slash - 1) = '\0'; + } + + return slash; +} + +static GPtrArray * +read_ip6_addresses (GKeyFile *file, + const char *setting_name, + const char *key) +{ + GPtrArray *addresses; + struct in6_addr addr; + guint32 prefix; + int i = 0; + + addresses = g_ptr_array_sized_new (3); + + /* Look for individual addresses */ + while (i++ < 1000) { + char *tmp, *key_name, *str_prefix; + int ret; + GValueArray *values; + GByteArray *address; + GValue value = { 0 }; + + key_name = g_strdup_printf ("%s%d", key, i); + tmp = g_key_file_get_string (file, setting_name, key_name, NULL); + g_free (key_name); + + if (!tmp) + break; /* all done */ + + /* convert the string array into IPv6 addresses */ + values = g_value_array_new (2); /* NMIP6Address has 2 items */ + + /* Split the address and prefix */ + str_prefix = split_prefix (tmp); + + /* address */ + ret = inet_pton (AF_INET6, tmp, &addr); + if (ret <= 0) { + g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp); + g_value_array_free (values); + goto next; + } + address = g_byte_array_new (); + g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); + g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); + g_value_take_boxed (&value, address); + g_value_array_append (values, &value); + g_value_unset (&value); + + /* prefix */ + prefix = 0; + if (str_prefix) { + if (!get_one_int (str_prefix, 128, key_name, &prefix)) { + g_value_array_free (values); + goto next; + } + } else { + /* Missing prefix defaults to /64 */ + prefix = 64; + } + + g_value_init (&value, G_TYPE_UINT); + g_value_set_uint (&value, prefix); + g_value_array_append (values, &value); + g_value_unset (&value); + + g_ptr_array_add (addresses, values); + +next: + g_free (tmp); + } + + if (addresses->len < 1) { + g_ptr_array_free (addresses, TRUE); + addresses = NULL; + } + + return addresses; +} + +static void +ip6_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) +{ + GPtrArray *addresses; + const char *setting_name = nm_setting_get_name (setting); + + addresses = read_ip6_addresses (keyfile, setting_name, key); + + if (addresses) { + g_object_set (setting, key, addresses, NULL); + g_ptr_array_foreach (addresses, free_one_ip6_address, NULL); + g_ptr_array_free (addresses, TRUE); + } +} + +static void +free_one_ip6_route (gpointer data, gpointer user_data) +{ + g_value_array_free ((GValueArray *) data); +} + +static GPtrArray * +read_ip6_routes (GKeyFile *file, + const char *setting_name, + const char *key) +{ + GPtrArray *routes; + struct in6_addr addr; + guint32 prefix, metric; + int i = 0; + + routes = g_ptr_array_sized_new (3); + + /* Look for individual routes */ + while (i++ < 1000) { + gchar **tmp; + char *key_name, *str_prefix; + gsize length = 0; + int ret; + GValueArray *values; + GByteArray *address; + GValue value = { 0 }; + + key_name = g_strdup_printf ("%s%d", key, i); + tmp = g_key_file_get_string_list (file, setting_name, key_name, &length, NULL); + g_free (key_name); + + if (!tmp || !length) + break; /* all done */ + + if (length != 3) { + g_warning ("%s: ignoring invalid IPv6 address item '%s'", __func__, key_name); + goto next; + } + + /* convert the string array into IPv6 routes */ + values = g_value_array_new (4); /* NMIP6Route has 4 items */ + + /* Split the route and prefix */ + str_prefix = split_prefix (tmp[0]); + + /* destination address */ + ret = inet_pton (AF_INET6, tmp[0], &addr); + if (ret <= 0) { + g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[0]); + g_value_array_free (values); + goto next; + } + address = g_byte_array_new (); + g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); + g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); + g_value_take_boxed (&value, address); + g_value_array_append (values, &value); + g_value_unset (&value); + + /* prefix */ + prefix = 0; + if (str_prefix) { + if (!get_one_int (str_prefix, 128, key_name, &prefix)) { + g_value_array_free (values); + goto next; + } + } else { + /* default to 64 if unspecified */ + prefix = 64; + } + g_value_init (&value, G_TYPE_UINT); + g_value_set_uint (&value, prefix); + g_value_array_append (values, &value); + g_value_unset (&value); + + /* next hop address */ + ret = inet_pton (AF_INET6, tmp[1], &addr); + if (ret <= 0) { + g_warning ("%s: ignoring invalid IPv6 %s element '%s'", __func__, key_name, tmp[1]); + g_value_array_free (values); + goto next; + } + address = g_byte_array_new (); + g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); + g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); + g_value_take_boxed (&value, address); + g_value_array_append (values, &value); + g_value_unset (&value); + + /* metric */ + metric = 0; + if (!get_one_int (tmp[2], G_MAXUINT32, key_name, &metric)) { + g_value_array_free (values); + goto next; + } + g_value_init (&value, G_TYPE_UINT); + g_value_set_uint (&value, metric); + g_value_array_append (values, &value); + g_value_unset (&value); + + g_ptr_array_add (routes, values); + +next: + g_strfreev (tmp); + } + + if (routes->len < 1) { + g_ptr_array_free (routes, TRUE); + routes = NULL; + } + + return routes; +} + +static void +ip6_route_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) +{ + GPtrArray *routes; + const char *setting_name = nm_setting_get_name (setting); + + routes = read_ip6_routes (keyfile, setting_name, key); + + if (routes) { + g_object_set (setting, key, routes, NULL); + g_ptr_array_foreach (routes, free_one_ip6_route, NULL); + g_ptr_array_free (routes, TRUE); + } +} + +static void +free_one_ip6_dns (gpointer data, gpointer user_data) +{ + g_byte_array_free ((GByteArray *) data, TRUE); +} + +static void +ip6_dns_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) +{ + const char *setting_name = nm_setting_get_name (setting); + GPtrArray *array = NULL; + gsize length; + char **list, **iter; + int ret; + + list = g_key_file_get_string_list (keyfile, setting_name, key, &length, NULL); + if (!list || !g_strv_length (list)) + return; + + array = g_ptr_array_sized_new (length); + for (iter = list; *iter; iter++) { + GByteArray *byte_array; + struct in6_addr addr; + + ret = inet_pton (AF_INET6, *iter, &addr); + if (ret <= 0) { + g_warning ("%s: ignoring invalid DNS server IPv6 address '%s'", __func__, *iter); + continue; + } + byte_array = g_byte_array_new (); + g_byte_array_append (byte_array, (guint8 *) addr.s6_addr, 16); + + g_ptr_array_add (array, byte_array); + } + g_strfreev (list); + + if (array) { + g_object_set (setting, key, array, NULL); + g_ptr_array_foreach (array, free_one_ip6_dns, NULL); + g_ptr_array_free (array, TRUE); + } +} static void mac_address_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) @@ -407,22 +697,35 @@ typedef struct { /* A table of keys that require further parsing/conversion becuase they are * stored in a format that can't be automatically read using the key's type. - * i.e. IP addresses, which are stored in NetworkManager as guint32, but are - * stored in keyfiles as strings, eg "10.1.1.2". + * i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are + * stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored + * in struct in6_addr internally, but as string in keyfiles. */ static KeyParser key_parsers[] = { { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES, FALSE, ip4_addr_parser }, + { NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES, + FALSE, + ip6_addr_parser }, { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ROUTES, FALSE, ip4_route_parser }, + { NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ROUTES, + FALSE, + ip6_route_parser }, { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_DNS, FALSE, ip4_dns_parser }, + { NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS, + FALSE, + ip6_dns_parser }, { NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS, TRUE, diff --git a/system-settings/plugins/keyfile/io/writer.c b/system-settings/plugins/keyfile/io/writer.c index efa5d1d4e5..d9f36af7a6 100644 --- a/system-settings/plugins/keyfile/io/writer.c +++ b/system-settings/plugins/keyfile/io/writer.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. */ #include @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -184,6 +185,189 @@ ip4_route_writer (GKeyFile *file, write_ip4_values (file, setting_name, key, array, 4, 0, 2); } +static void +ip6_dns_writer (GKeyFile *file, + NMSetting *setting, + const char *key, + const GValue *value) +{ + GPtrArray *array; + GByteArray *byte_array; + char **list; + int i, num = 0; + + g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR)); + + array = (GPtrArray *) g_value_get_boxed (value); + if (!array || !array->len) + return; + + list = g_new0 (char *, array->len + 1); + + for (i = 0; i < array->len; i++) { + char buf[INET6_ADDRSTRLEN]; + + byte_array = g_ptr_array_index (array, i); + if (!inet_ntop (AF_INET6, (struct in6_addr *) byte_array->data, buf, sizeof (buf))) { + int j; + GString *ip6_str = g_string_new (NULL); + g_string_append_printf (ip6_str, "%02X", byte_array->data[0]); + for (j = 1; j < 16; j++) + g_string_append_printf (ip6_str, " %02X", byte_array->data[j]); + nm_warning ("%s: error converting IP6 address %s", + __func__, ip6_str->str); + g_string_free (ip6_str, TRUE); + } else + list[num++] = g_strdup (buf); + } + + g_key_file_set_string_list (file, nm_setting_get_name (setting), key, (const char **) list, num); + g_strfreev (list); +} + +static gboolean +ip6_array_to_addr (GValueArray *values, guint32 idx, char *buf, size_t buflen) +{ + GByteArray *byte_array; + GValue *addr_val; + + g_return_val_if_fail (buflen >= INET6_ADDRSTRLEN, FALSE); + + /* address */ + addr_val = g_value_array_get_nth (values, idx); + byte_array = g_value_get_boxed (addr_val); + errno = 0; + if (!inet_ntop (AF_INET6, (struct in6_addr *) byte_array->data, buf, buflen)) { + GString *ip6_str = g_string_sized_new (INET6_ADDRSTRLEN + 10); + + /* error converting the address */ + g_string_append_printf (ip6_str, "%02X", byte_array->data[0]); + for (idx = 1; idx < 16; idx++) + g_string_append_printf (ip6_str, " %02X", byte_array->data[idx]); + nm_warning ("%s: error %d converting IP6 address %s", + __func__, errno, ip6_str->str); + g_string_free (ip6_str, TRUE); + return FALSE; + } + + return TRUE; +} + +static char * +ip6_array_to_addr_prefix (GValueArray *values) +{ + GValue *prefix_val; + char *ret = NULL; + GString *ip6_str; + char buf[INET6_ADDRSTRLEN]; + + /* address */ + if (ip6_array_to_addr (values, 0, buf, sizeof (buf))) { + /* Enough space for the address, '/', and the prefix */ + ip6_str = g_string_sized_new (INET6_ADDRSTRLEN + 5); + + /* prefix */ + g_string_append (ip6_str, buf); + prefix_val = g_value_array_get_nth (values, 1); + g_string_append_printf (ip6_str, "/%u", g_value_get_uint (prefix_val)); + + ret = ip6_str->str; + g_string_free (ip6_str, FALSE); + } + + return ret; +} + +static void +ip6_addr_writer (GKeyFile *file, + NMSetting *setting, + const char *key, + const GValue *value) +{ + GPtrArray *array; + const char *setting_name = nm_setting_get_name (setting); + int i, j; + + g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS)); + + array = (GPtrArray *) g_value_get_boxed (value); + if (!array || !array->len) + return; + + for (i = 0, j = 1; i < array->len; i++) { + GValueArray *values = g_ptr_array_index (array, i); + char *key_name, *ip6_addr; + + if (values->n_values % 2) { + nm_warning ("%s: error writing IP6 address %d; address array length" + " %d is not a multiple of 2.", + __func__, i, values->n_values); + continue; + } + + ip6_addr = ip6_array_to_addr_prefix (values); + if (ip6_addr) { + /* Write it out */ + key_name = g_strdup_printf ("%s%d", key, j++); + g_key_file_set_string (file, setting_name, key_name, ip6_addr); + g_free (key_name); + g_free (ip6_addr); + } + } +} + +static void +ip6_route_writer (GKeyFile *file, + NMSetting *setting, + const char *key, + const GValue *value) +{ + GPtrArray *array; + const char *setting_name = nm_setting_get_name (setting); + char *list[3]; + int i, j; + + g_return_if_fail (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE)); + + array = (GPtrArray *) g_value_get_boxed (value); + if (!array || !array->len) + return; + + for (i = 0, j = 1; i < array->len; i++) { + GValueArray *values = g_ptr_array_index (array, i); + char *key_name; + guint32 int_val; + char buf[INET6_ADDRSTRLEN]; + + memset (list, 0, sizeof (list)); + + /* Address and prefix */ + list[0] = ip6_array_to_addr_prefix (values); + if (!list[0]) + continue; + + /* Next Hop */ + if (!ip6_array_to_addr (values, 2, buf, sizeof (buf))) + continue; + list[1] = g_strdup (buf); + + /* Metric */ + value = g_value_array_get_nth (values, 3); + int_val = g_value_get_uint (value); + list[2] = g_strdup_printf ("%d", int_val); + + /* Write it out */ + key_name = g_strdup_printf ("%s%d", key, j++); + g_key_file_set_string_list (file, setting_name, key_name, (const char **) list, 3); + g_free (key_name); + + g_free (list[0]); + g_free (list[1]); + g_free (list[2]); + } +} + + static void mac_address_writer (GKeyFile *file, NMSetting *setting, @@ -259,19 +443,29 @@ typedef struct { /* A table of keys that require further parsing/conversion becuase they are * stored in a format that can't be automatically read using the key's type. - * i.e. IP addresses, which are stored in NetworkManager as guint32, but are - * stored in keyfiles as strings, eg "10.1.1.2". + * i.e. IPv4 addresses, which are stored in NetworkManager as guint32, but are + * stored in keyfiles as strings, eg "10.1.1.2" or IPv6 addresses stored + * in struct in6_addr internally, but as string in keyfiles. */ static KeyWriter key_writers[] = { { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES, ip4_addr_writer }, + { NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES, + ip6_addr_writer }, { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ROUTES, ip4_route_writer }, + { NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ROUTES, + ip6_route_writer }, { NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_DNS, ip4_dns_writer }, + { NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS, + ip6_dns_writer }, { NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS, mac_address_writer }, diff --git a/system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection index f542811551..5785dc2485 100644 --- a/system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection +++ b/system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection @@ -20,3 +20,13 @@ addresses1=192.168.0.5;24;192.168.0.1; addresses2=1.2.3.4;16;1.2.1.1; ignore-auto-routes=false ignore-auto-dns=false + +[ipv6] +method=manual +dns=1111:dddd::aaaa;1::cafe; +dns-search=super-domain.com;redhat.com;gnu.org; +addresses1=abcd:1234:ffff::cdde/64 +addresses2=1:2:3:4:5:6:7:8/96 +routes1=a:b:c:d::/64;f:e:d:c:1:2:3:4;99; +ignore-auto-routes=false +ignore-auto-dns=false diff --git a/system-settings/plugins/keyfile/tests/test-keyfile.c b/system-settings/plugins/keyfile/tests/test-keyfile.c index 0f8c2ccbe3..58ec940301 100644 --- a/system-settings/plugins/keyfile/tests/test-keyfile.c +++ b/system-settings/plugins/keyfile/tests/test-keyfile.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "nm-test-helpers.h" @@ -50,6 +51,7 @@ test_read_valid_wired_connection (void) NMSettingConnection *s_con; NMSettingWired *s_wired; NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; GError *error = NULL; const GByteArray *array; char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; @@ -66,6 +68,18 @@ test_read_valid_wired_connection (void) const char *expected_address1_gw = "192.168.0.1"; const char *expected_address2_gw = "1.2.1.1"; NMIP4Address *ip4_addr; + const char *expected6_dns1 = "1111:dddd::aaaa"; + const char *expected6_dns2 = "1::cafe"; + const char *expected6_dnssearch1 = "super-domain.com"; + const char *expected6_dnssearch2 = "redhat.com"; + const char *expected6_dnssearch3 = "gnu.org"; + struct in6_addr addr6; + const char *expected6_address1 = "abcd:1234:ffff::cdde"; + const char *expected6_address2 = "1:2:3:4:5:6:7:8"; + const char *expected6_route_dest = "a:b:c:d::"; + const char *expected6_route_nh = "f:e:d:c:1:2:3:4"; + NMIP6Address *ip6_addr; + NMIP6Route *ip6_route; connection = connection_from_file (TEST_WIRED_FILE); ASSERT (connection != NULL, @@ -215,7 +229,7 @@ test_read_valid_wired_connection (void) NM_SETTING_IP4_CONFIG_ADDRESSES); ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 24, - "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1 gateway", + "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1 prefix", TEST_WIRED_FILE, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); @@ -251,7 +265,7 @@ test_read_valid_wired_connection (void) NM_SETTING_IP4_CONFIG_ADDRESSES); ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 16, - "connection-verify-wired", "failed to verify %s: unexpected IP4 address #2 gateway", + "connection-verify-wired", "failed to verify %s: unexpected IP4 address #2 prefix", TEST_WIRED_FILE, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); @@ -278,6 +292,172 @@ test_read_valid_wired_connection (void) NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); + /* ===== IPv6 SETTING ===== */ + + s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG)); + ASSERT (s_ip6 != NULL, + "connection-verify-ip6", "failed to verify %s: missing %s setting", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME); + + /* Method */ + tmp = nm_setting_ip6_config_get_method (s_ip6); + ASSERT (strcmp (tmp, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_METHOD); + + /* DNS Addresses */ + ASSERT (nm_setting_ip6_config_get_num_dns (s_ip6) == 2, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + + ASSERT (inet_pton (AF_INET6, expected6_dns1, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert DNS IP6 address #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_setting_ip6_config_get_dns (s_ip6, 0), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + + ASSERT (inet_pton (AF_INET6, expected6_dns2, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert DNS IP address #2", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_setting_ip6_config_get_dns (s_ip6, 1), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value #2", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + + ASSERT (nm_setting_ip6_config_get_num_addresses (s_ip6) == 2, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + + /* DNS Searches */ + ASSERT (nm_setting_ip6_config_get_num_dns_searches (s_ip6) == 3, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS_SEARCH); + + ASSERT (!strcmp (nm_setting_ip6_config_get_dns_search (s_ip6, 0), expected6_dnssearch1), + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS_SEARCH); + ASSERT (!strcmp (nm_setting_ip6_config_get_dns_search (s_ip6, 1), expected6_dnssearch2), + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value #2", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS_SEARCH); + ASSERT (!strcmp (nm_setting_ip6_config_get_dns_search (s_ip6, 2), expected6_dnssearch3), + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value #3", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS_SEARCH); + + /* Address #1 */ + ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 0); + ASSERT (ip6_addr, + "connection-verify-wired", "failed to verify %s: missing IP6 address #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + ASSERT (nm_ip6_address_get_prefix (ip6_addr) == 64, + "connection-verify-wired", "failed to verify %s: unexpected IP6 address #1 prefix", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET6, expected6_address1, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert IP address #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + /* Address #2 */ + ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 1); + ASSERT (ip6_addr, + "connection-verify-wired", "failed to verify %s: missing IP6 address #2", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + ASSERT (nm_ip6_address_get_prefix (ip6_addr) == 96, + "connection-verify-wired", "failed to verify %s: unexpected IP6 address #2 prefix", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET6, expected6_address2, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert IP address #2", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected IP6 address #2", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + /* Route #1 */ + ip6_route = nm_setting_ip6_config_get_route (s_ip6, 0); + ASSERT (ip6_route, + "connection-verify-wired", "failed to verify %s: missing IP6 route #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ROUTES); + + ASSERT (inet_pton (AF_INET6, expected6_route_dest, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert IP route dest #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_route_get_dest (ip6_route), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected IP4 route dest #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ROUTES); + + ASSERT (nm_ip6_route_get_prefix (ip6_route) == 64, + "connection-verify-wired", "failed to verify %s: unexpected IP6 route #1 prefix", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ROUTES); + + ASSERT (inet_pton (AF_INET6, expected6_route_nh, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert IP route next hop #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_route_get_next_hop (ip6_route), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected IP4 route dest #1", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ROUTES); + + ASSERT (nm_ip6_route_get_metric (ip6_route) == 99, + "connection-verify-wired", "failed to verify %s: unexpected IP6 route #1 metric", + TEST_WIRED_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ROUTES); + g_object_unref (connection); } @@ -327,6 +507,49 @@ add_one_ip4_route (NMSettingIP4Config *s_ip4, nm_ip4_route_unref (route); } +static void +add_one_ip6_address (NMSettingIP6Config *s_ip6, + const char *addr, + guint32 prefix) +{ + struct in6_addr tmp; + NMIP6Address *ip6_addr; + + ip6_addr = nm_ip6_address_new (); + nm_ip6_address_set_prefix (ip6_addr, prefix); + + inet_pton (AF_INET6, addr, &tmp); + nm_ip6_address_set_address (ip6_addr, &tmp); + + nm_setting_ip6_config_add_address (s_ip6, ip6_addr); + nm_ip6_address_unref (ip6_addr); +} + +static void +add_one_ip6_route (NMSettingIP6Config *s_ip6, + const char *dest, + const char *nh, + guint32 prefix, + guint32 metric) +{ + struct in6_addr addr; + NMIP6Route *route; + + route = nm_ip6_route_new (); + nm_ip6_route_set_prefix (route, prefix); + nm_ip6_route_set_metric (route, metric); + + inet_pton (AF_INET6, dest, &addr); + nm_ip6_route_set_dest (route, &addr); + + inet_pton (AF_INET6, nh, &addr); + nm_ip6_route_set_next_hop (route, &addr); + + nm_setting_ip6_config_add_route (s_ip6, route); + nm_ip6_route_unref (route); +} + + static void test_write_wired_connection (void) { @@ -334,6 +557,7 @@ test_write_wired_connection (void) NMSettingConnection *s_con; NMSettingWired *s_wired; NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; char *uuid; GByteArray *mac; unsigned char tmpmac[] = { 0x99, 0x88, 0x77, 0x66, 0x55, 0x44 }; @@ -344,6 +568,7 @@ test_write_wired_connection (void) pid_t owner_grp; uid_t owner_uid; struct in_addr addr; + struct in6_addr addr6; const char *dns1 = "4.2.2.1"; const char *dns2 = "4.2.2.2"; const char *address1 = "192.168.0.5"; @@ -354,6 +579,14 @@ test_write_wired_connection (void) const char *route1_nh = "10.10.10.1"; const char *route2 = "0.0.0.0"; const char *route2_nh = "1.2.1.1"; + const char *dns6_1 = "1::cafe"; + const char *dns6_2 = "2::cafe"; + const char *address6_1 = "abcd::beef"; + const char *address6_2 = "dcba::beef"; + const char *route6_1 = "1:2:3:4:5:6:7:8"; + const char *route6_1_nh = "8:7:6:5:4:3:2:1"; + const char *route6_2 = "::"; + const char *route6_2_nh = "2001::1111"; guint64 timestamp = 0x12345678L; connection = nm_connection_new (); @@ -420,6 +653,35 @@ test_write_wired_connection (void) inet_pton (AF_INET, dns2, &addr); nm_setting_ip4_config_add_dns (s_ip4, addr.s_addr); + /* IP6 setting */ + + s_ip6 = NM_SETTING_IP6_CONFIG (nm_setting_ip6_config_new ()); + ASSERT (s_ip6 != NULL, + "connection-write", "failed to allocate new %s setting", + NM_SETTING_IP6_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, + NULL); + + /* Addresses */ + add_one_ip6_address (s_ip6, address6_1, 64); + add_one_ip6_address (s_ip6, address6_2, 56); + + /* Routes */ + add_one_ip6_route (s_ip6, route6_1, route6_1_nh, 64, 3); + add_one_ip6_route (s_ip6, route6_2, route6_2_nh, 56, 1); + + /* DNS servers */ + inet_pton (AF_INET6, dns6_1, &addr6); + nm_setting_ip6_config_add_dns (s_ip6, &addr6); + inet_pton (AF_INET6, dns6_2, &addr6); + nm_setting_ip6_config_add_dns (s_ip6, &addr6); + + /* DNS searches */ + nm_setting_ip6_config_add_dns_search (s_ip6, "wallaceandgromit.com"); + /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); @@ -570,6 +832,7 @@ test_write_wireless_connection (void) NMSettingConnection *s_con; NMSettingWireless *s_wireless; NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; char *uuid; GByteArray *bssid; unsigned char tmpbssid[] = { 0xaa, 0xb9, 0xa1, 0x74, 0x55, 0x44 }; @@ -640,6 +903,18 @@ test_write_wireless_connection (void) NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + /* IP6 setting */ + + s_ip6 = NM_SETTING_IP6_CONFIG (nm_setting_ip6_config_new ()); + ASSERT (s_ip6 != NULL, + "connection-write", "failed to allocate new %s setting", + NM_SETTING_IP6_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NULL); + /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); @@ -688,6 +963,7 @@ int main (int argc, char **argv) base = g_path_get_basename (argv[0]); fprintf (stdout, "%s: SUCCESS\n", base); g_free (base); + dbus_g_connection_unref (bus); return 0; }