keyfile: fix for IPv6 address gateways

This commit is contained in:
Dan Williams 2010-05-03 04:53:13 -07:00
parent 0ab71998ce
commit 719738d133
5 changed files with 362 additions and 16 deletions

View file

@ -337,13 +337,30 @@ split_prefix (char *addr)
return slash;
}
static char *
split_gw (char *str)
{
char *comma;
g_return_val_if_fail (str != NULL, NULL);
/* Find the prefix and split the string */
comma = strchr (str, ',');
if (comma && comma > str) {
comma++;
*(comma - 1) = '\0';
return comma;
}
return NULL;
}
static GPtrArray *
read_ip6_addresses (GKeyFile *file,
const char *setting_name,
const char *key)
{
GPtrArray *addresses;
struct in6_addr addr;
struct in6_addr addr, gw;
guint32 prefix;
int i = 0;
@ -351,10 +368,11 @@ read_ip6_addresses (GKeyFile *file,
/* Look for individual addresses */
while (i++ < 1000) {
char *tmp, *key_name, *str_prefix;
char *tmp, *key_name, *str_prefix, *str_gw;
int ret;
GValueArray *values;
GByteArray *address;
GByteArray *gateway;
GValue value = { 0 };
key_name = g_strdup_printf ("%s%d", key, i);
@ -377,6 +395,7 @@ read_ip6_addresses (GKeyFile *file,
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);
@ -401,6 +420,26 @@ read_ip6_addresses (GKeyFile *file,
g_value_array_append (values, &value);
g_value_unset (&value);
/* Gateway (optional) */
str_gw = split_gw (str_prefix);
if (str_gw) {
ret = inet_pton (AF_INET6, str_gw, &gw);
if (ret <= 0) {
g_warning ("%s: ignoring invalid IPv6 %s gateway '%s'", __func__, key_name, tmp);
g_value_array_free (values);
goto next;
}
if (!IN6_IS_ADDR_UNSPECIFIED (&gw)) {
gateway = g_byte_array_new ();
g_byte_array_append (gateway, (guint8 *) gw.s6_addr, 16);
g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY);
g_value_take_boxed (&value, gateway);
g_value_array_append (values, &value);
g_value_unset (&value);
}
}
g_ptr_array_add (addresses, values);
next:
@ -422,7 +461,6 @@ ip6_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile)
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);

View file

@ -226,18 +226,27 @@ ip6_dns_writer (GKeyFile *file,
}
static gboolean
ip6_array_to_addr (GValueArray *values, guint32 idx, char *buf, size_t buflen)
ip6_array_to_addr (GValueArray *values,
guint32 idx,
char *buf,
size_t buflen,
gboolean *out_is_unspec)
{
GByteArray *byte_array;
GValue *addr_val;
struct in6_addr *addr;
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);
addr = (struct in6_addr *) byte_array->data;
if (out_is_unspec && IN6_IS_ADDR_UNSPECIFIED (addr))
*out_is_unspec = TRUE;
errno = 0;
if (!inet_ntop (AF_INET6, (struct in6_addr *) byte_array->data, buf, buflen)) {
if (!inet_ntop (AF_INET6, addr, buf, buflen)) {
GString *ip6_str = g_string_sized_new (INET6_ADDRSTRLEN + 10);
/* error converting the address */
@ -259,18 +268,24 @@ ip6_array_to_addr_prefix (GValueArray *values)
GValue *prefix_val;
char *ret = NULL;
GString *ip6_str;
char buf[INET6_ADDRSTRLEN];
char buf[INET6_ADDRSTRLEN + 1];
gboolean is_unspec = FALSE;
/* address */
if (ip6_array_to_addr (values, 0, buf, sizeof (buf))) {
if (ip6_array_to_addr (values, 0, buf, sizeof (buf), NULL)) {
/* Enough space for the address, '/', and the prefix */
ip6_str = g_string_sized_new (INET6_ADDRSTRLEN + 5);
ip6_str = g_string_sized_new ((INET6_ADDRSTRLEN * 2) + 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));
if (ip6_array_to_addr (values, 2, buf, sizeof (buf), &is_unspec)) {
if (!is_unspec)
g_string_append_printf (ip6_str, ",%s", buf);
}
ret = ip6_str->str;
g_string_free (ip6_str, FALSE);
}
@ -337,7 +352,8 @@ ip6_route_writer (GKeyFile *file,
GValueArray *values = g_ptr_array_index (array, i);
char *key_name;
guint32 int_val;
char buf[INET6_ADDRSTRLEN];
char buf[INET6_ADDRSTRLEN + 1];
gboolean is_unspec = FALSE;
memset (list, 0, sizeof (list));
@ -347,7 +363,9 @@ ip6_route_writer (GKeyFile *file,
continue;
/* Next Hop */
if (!ip6_array_to_addr (values, 2, buf, sizeof (buf)))
if (!ip6_array_to_addr (values, 2, buf, sizeof (buf), &is_unspec))
continue;
if (is_unspec)
continue;
list[1] = g_strdup (buf);

View file

@ -2,7 +2,8 @@ EXTRA_DIST = \
Test_Wired_Connection \
Test_GSM_Connection \
Test_Wireless_Connection \
Test_Wired_Connection_MAC_Case
Test_Wired_Connection_MAC_Case \
Test_Wired_Connection_IP6
check-local:
@for f in $(EXTRA_DIST); do \

View file

@ -0,0 +1,20 @@
[connection]
id=Test Wired Connection IP6
uuid=4e80a56d-c99f-4aad-a6dd-b449bc398c57
type=802-3-ethernet
autoconnect=true
timestamp=6654332
[802-3-ethernet]
auto-negotiate=true
mtu=1400
[ipv4]
method=disabled
[ipv6]
method=manual
addresses1=abcd:1234:ffff::cdde/64,abcd:1234:ffff::cdd1
dns=1111:dddd::aaaa;1::cafe;

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 Red Hat, Inc.
* Copyright (C) 2008 - 2010 Red Hat, Inc.
*/
#include <stdio.h>
@ -510,7 +510,8 @@ add_one_ip4_route (NMSettingIP4Config *s_ip4,
static void
add_one_ip6_address (NMSettingIP6Config *s_ip6,
const char *addr,
guint32 prefix)
guint32 prefix,
const char *gw)
{
struct in6_addr tmp;
NMIP6Address *ip6_addr;
@ -521,6 +522,11 @@ add_one_ip6_address (NMSettingIP6Config *s_ip6,
inet_pton (AF_INET6, addr, &tmp);
nm_ip6_address_set_address (ip6_addr, &tmp);
if (gw) {
inet_pton (AF_INET6, gw, &tmp);
nm_ip6_address_set_gateway (ip6_addr, &tmp);
}
nm_setting_ip6_config_add_address (s_ip6, ip6_addr);
nm_ip6_address_unref (ip6_addr);
}
@ -666,8 +672,8 @@ test_write_wired_connection (void)
NULL);
/* Addresses */
add_one_ip6_address (s_ip6, address6_1, 64);
add_one_ip6_address (s_ip6, address6_2, 56);
add_one_ip6_address (s_ip6, address6_1, 64, NULL);
add_one_ip6_address (s_ip6, address6_2, 56, NULL);
/* Routes */
add_one_ip6_route (s_ip6, route6_1, route6_1_nh, 64, 3);
@ -708,6 +714,266 @@ test_write_wired_connection (void)
g_object_unref (connection);
}
#define TEST_WIRED_IP6_FILE TEST_KEYFILES_DIR"/Test_Wired_Connection_IP6"
static void
test_read_ip6_wired_connection (void)
{
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingWired *s_wired;
NMSettingIP4Config *s_ip4;
NMSettingIP6Config *s_ip6;
GError *error = NULL;
const char *tmp;
const char *expected_id = "Test Wired Connection IP6";
const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57";
struct in6_addr addr6;
const char *expected6_address1 = "abcd:1234:ffff::cdde";
const char *expected6_gw1 = "abcd:1234:ffff::cdd1";
NMIP6Address *ip6_addr;
connection = connection_from_file (TEST_WIRED_IP6_FILE);
ASSERT (connection != NULL,
"connection-read", "failed to read %s", TEST_WIRED_IP6_FILE);
ASSERT (nm_connection_verify (connection, &error),
"connection-verify", "failed to verify %s: %s", TEST_WIRED_IP6_FILE, error->message);
/* ===== CONNECTION SETTING ===== */
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
ASSERT (s_con != NULL,
"connection-verify-connection", "failed to verify %s: missing %s setting",
TEST_WIRED_IP6_FILE,
NM_SETTING_CONNECTION_SETTING_NAME);
/* ID */
tmp = nm_setting_connection_get_id (s_con);
ASSERT (tmp != NULL,
"connection-verify-connection", "failed to verify %s: missing %s / %s key",
TEST_WIRED_IP6_FILE,
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_ID);
ASSERT (strcmp (tmp, expected_id) == 0,
"connection-verify-connection", "failed to verify %s: unexpected %s / %s key value",
TEST_WIRED_IP6_FILE,
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_ID);
/* UUID */
tmp = nm_setting_connection_get_uuid (s_con);
ASSERT (tmp != NULL,
"connection-verify-connection", "failed to verify %s: missing %s / %s key",
TEST_WIRED_IP6_FILE,
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_UUID);
ASSERT (strcmp (tmp, expected_uuid) == 0,
"connection-verify-connection", "failed to verify %s: unexpected %s / %s key value",
TEST_WIRED_IP6_FILE,
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_UUID);
/* ===== WIRED SETTING ===== */
s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
ASSERT (s_wired != NULL,
"connection-verify-wired", "failed to verify %s: missing %s setting",
TEST_WIRED_IP6_FILE,
NM_SETTING_WIRED_SETTING_NAME);
/* ===== IPv4 SETTING ===== */
s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
ASSERT (s_ip4 != NULL,
"connection-verify-ip4", "failed to verify %s: missing %s setting",
TEST_WIRED_IP6_FILE,
NM_SETTING_IP4_CONFIG_SETTING_NAME);
/* Method */
tmp = nm_setting_ip4_config_get_method (s_ip4);
ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0,
"connection-verify-wired", "failed to verify %s: unexpected %s / %s key value",
TEST_WIRED_IP6_FILE,
NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_SETTING_IP4_CONFIG_METHOD);
ASSERT (nm_setting_ip4_config_get_num_addresses (s_ip4) == 0,
"connection-verify-wired", "failed to verify %s: unexpected %s / %s key value",
TEST_WIRED_IP6_FILE,
NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_SETTING_IP4_CONFIG_DNS);
/* ===== 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_IP6_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_IP6_FILE,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_METHOD);
ASSERT (nm_setting_ip6_config_get_num_addresses (s_ip6) == 1,
"connection-verify-wired", "failed to verify %s: unexpected %s / %s key value",
TEST_WIRED_IP6_FILE,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_DNS);
/* 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_IP6_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_IP6_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_IP6_FILE,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_ADDRESSES);
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_IP6_FILE,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_ADDRESSES);
ASSERT (inet_pton (AF_INET6, expected6_gw1, &addr6) > 0,
"connection-verify-wired", "failed to verify %s: couldn't convert GW address #1",
TEST_WIRED_IP6_FILE,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_ADDRESSES);
ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_gateway (ip6_addr), &addr6),
"connection-verify-wired", "failed to verify %s: unexpected IP4 address #1",
TEST_WIRED_IP6_FILE,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_ADDRESSES);
g_object_unref (connection);
}
static void
test_write_ip6_wired_connection (void)
{
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingWired *s_wired;
NMSettingIP4Config *s_ip4;
NMSettingIP6Config *s_ip6;
char *uuid;
gboolean success;
NMConnection *reread;
char *testfile = NULL;
GError *error = NULL;
pid_t owner_grp;
uid_t owner_uid;
struct in6_addr addr6;
const char *dns = "1::cafe";
const char *address = "abcd::beef";
const char *gw = "dcba::beef";
connection = nm_connection_new ();
ASSERT (connection != NULL,
"connection-write", "failed to allocate new connection");
/* Connection setting */
s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
ASSERT (s_con != NULL,
"connection-write", "failed to allocate new %s setting",
NM_SETTING_CONNECTION_SETTING_NAME);
nm_connection_add_setting (connection, NM_SETTING (s_con));
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
NM_SETTING_CONNECTION_ID, "Work Wired IP6",
NM_SETTING_CONNECTION_UUID, uuid,
NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
NULL);
g_free (uuid);
/* Wired setting */
s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
ASSERT (s_wired != NULL,
"connection-write", "failed to allocate new %s setting",
NM_SETTING_WIRED_SETTING_NAME);
nm_connection_add_setting (connection, NM_SETTING (s_wired));
/* IP4 setting */
s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
ASSERT (s_ip4 != NULL,
"connection-write", "failed to allocate new %s setting",
NM_SETTING_IP4_CONFIG_SETTING_NAME);
nm_connection_add_setting (connection, NM_SETTING (s_ip4));
g_object_set (s_ip4,
NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
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_MANUAL,
NULL);
/* Addresses */
add_one_ip6_address (s_ip6, address, 64, gw);
/* DNS servers */
inet_pton (AF_INET6, dns, &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 ();
success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error);
ASSERT (success == TRUE,
"connection-write", "failed to allocate write keyfile: %s",
error ? error->message : "(none)");
ASSERT (testfile != NULL,
"connection-write", "didn't get keyfile name back after writing connection");
/* Read the connection back in and compare it to the one we just wrote out */
reread = connection_from_file (testfile);
ASSERT (reread != NULL, "connection-write", "failed to re-read test connection");
ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
"connection-write", "written and re-read connection weren't the same");
g_clear_error (&error);
unlink (testfile);
g_free (testfile);
g_object_unref (reread);
g_object_unref (connection);
}
#define TEST_WIRED_MAC_CASE_FILE TEST_KEYFILES_DIR"/Test_Wired_Connection_MAC_Case"
static void
@ -1042,6 +1308,9 @@ int main (int argc, char **argv)
test_read_valid_wired_connection ();
test_write_wired_connection ();
test_read_ip6_wired_connection ();
test_write_ip6_wired_connection ();
test_read_wired_mac_case ();
test_read_valid_wireless_connection ();