From d8c9828a4d4cd0fdc0078ef74d18dc7c7968f1c9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Aug 2013 12:44:27 -0500 Subject: [PATCH] core: add nm_ip6_config_subtract() Removes anything in 'src' from 'dst'. --- .gitignore | 1 + src/nm-ip6-config.c | 188 ++++++++++++++++++++++++++++++++---- src/nm-ip6-config.h | 6 ++ src/tests/Makefile.am | 15 ++- src/tests/test-ip6-config.c | 176 +++++++++++++++++++++++++++++++++ 5 files changed, 363 insertions(+), 23 deletions(-) create mode 100644 src/tests/test-ip6-config.c diff --git a/.gitignore b/.gitignore index c50f763748..dd5021475d 100644 --- a/.gitignore +++ b/.gitignore @@ -179,6 +179,7 @@ valgrind-*.log /libnm-glib/tests/test-remote-settings-client /src/tests/test-dhcp-options /src/tests/test-ip4-config +/src/tests/test-ip6-config /src/tests/test-policy-hosts /src/tests/test-wifi-ap-utils /src/dhcp-manager/tests/test-dhcp-dhclient diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index e36630fe3f..86e6590c36 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -167,12 +167,6 @@ nm_ip6_config_commit (NMIP6Config *config, int ifindex, int priority) return success; } -static inline gboolean -ip6_addresses_equal (const struct in6_addr *a, const struct in6_addr *b) -{ - return memcmp (a, b, sizeof (struct in6_addr)) == 0; -} - void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting) { @@ -386,6 +380,115 @@ nm_ip6_config_destination_is_direct (NMIP6Config *config, const struct in6_addr return FALSE; } +static gboolean +routes_are_duplicate (NMPlatformIP6Route *a, NMPlatformIP6Route *b) +{ + return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen; +} + +/** + * nm_ip6_config_subtract() + * @dst: config from which to remove everything in @src + * @src: config to remove from @dst + * + * Removes everything in @src from @dst. + * + */ +void +nm_ip6_config_subtract (NMIP6Config *dst, NMIP6Config *src) +{ + guint32 i, j; + const struct in6_addr *dst_tmp, *src_tmp; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + /* addresses */ + for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++) { + const NMPlatformIP6Address *src_addr = nm_ip6_config_get_address (src, i); + + for (j = 0; j < nm_ip6_config_get_num_addresses (dst); j++) { + const NMPlatformIP6Address *dst_addr = nm_ip6_config_get_address (dst, j); + + if (IN6_ARE_ADDR_EQUAL (&src_addr->address, &dst_addr->address)) { + nm_ip6_config_del_address (dst, j); + break; + } + } + } + + /* ptp address */ + src_tmp = nm_ip6_config_get_ptp_address (src); + dst_tmp = nm_ip6_config_get_ptp_address (dst); + if (src_tmp && dst_tmp && IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp)) + nm_ip6_config_set_ptp_address (dst, NULL); + + /* nameservers */ + for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++) { + const struct in6_addr *src_ns = nm_ip6_config_get_nameserver (src, i); + + for (j = 0; j < nm_ip6_config_get_num_nameservers (dst); j++) { + const struct in6_addr *dst_ns = nm_ip6_config_get_nameserver (dst, j); + + if (IN6_ARE_ADDR_EQUAL (src_ns, dst_ns)) { + nm_ip6_config_del_nameserver (dst, j); + break; + } + } + } + + /* default gateway */ + src_tmp = nm_ip6_config_get_gateway (src); + dst_tmp = nm_ip6_config_get_gateway (dst); + if (src_tmp && dst_tmp && IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp)) + nm_ip6_config_set_gateway (dst, NULL); + + /* routes */ + for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) { + NMPlatformIP6Route *src_route = nm_ip6_config_get_route (src, i); + + for (j = 0; j < nm_ip6_config_get_num_routes (dst); j++) { + NMPlatformIP6Route *dst_route = nm_ip6_config_get_route (dst, j); + + if (routes_are_duplicate (src_route, dst_route)) { + nm_ip6_config_del_route (dst, j); + break; + } + } + } + + /* domains */ + for (i = 0; i < nm_ip6_config_get_num_domains (src); i++) { + const char *src_domain = nm_ip6_config_get_domain (src, i); + + for (j = 0; j < nm_ip6_config_get_num_domains (dst); j++) { + const char *dst_domain = nm_ip6_config_get_domain (dst, j); + + if (g_strcmp0 (src_domain, dst_domain) == 0) { + nm_ip6_config_del_domain (dst, j); + break; + } + } + } + + /* dns searches */ + for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) { + const char *src_search = nm_ip6_config_get_search (src, i); + + for (j = 0; j < nm_ip6_config_get_num_searches (dst); j++) { + const char *dst_search = nm_ip6_config_get_search (dst, j); + + if (g_strcmp0 (src_search, dst_search) == 0) { + nm_ip6_config_del_search (dst, j); + break; + } + } + } + + if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst)) + nm_ip6_config_set_mss (dst, 0); +} + /******************************************************************/ void @@ -433,12 +536,6 @@ nm_ip6_config_reset_addresses (NMIP6Config *config) g_array_set_size (priv->nameservers, 0); } -static gboolean -addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) -{ - return IN6_ARE_ADDR_EQUAL (&a->address, &b->address); -} - void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) { @@ -450,7 +547,8 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) for (i = 0; i < priv->addresses->len; i++ ) { NMPlatformIP6Address *item = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - if (addresses_are_duplicate (item, new)) { + if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { + /* Copy over old item to get new lifetime, timestamp, preferred */ memcpy (item, new, sizeof (*item)); return; } @@ -459,6 +557,16 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) g_array_append_val (priv->addresses, *new); } +void +nm_ip6_config_del_address (NMIP6Config *config, guint i) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->addresses->len); + + g_array_remove_index (priv->addresses, i); +} + guint nm_ip6_config_get_num_addresses (NMIP6Config *config) { @@ -485,12 +593,6 @@ nm_ip6_config_reset_routes (NMIP6Config *config) g_array_set_size (priv->routes, 0); } -static gboolean -routes_are_duplicate (NMPlatformIP6Route *a, NMPlatformIP6Route *b) -{ - return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen; -} - void nm_ip6_config_add_route (NMIP6Config *config, NMPlatformIP6Route *new) { @@ -511,6 +613,16 @@ nm_ip6_config_add_route (NMIP6Config *config, NMPlatformIP6Route *new) g_array_append_val (priv->routes, *new); } +void +nm_ip6_config_del_route (NMIP6Config *config, guint i) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->routes->len); + + g_array_remove_index (priv->routes, i); +} + guint nm_ip6_config_get_num_routes (NMIP6Config *config) { @@ -552,6 +664,16 @@ nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *new) g_array_append_val (priv->nameservers, *new); } +void +nm_ip6_config_del_nameserver (NMIP6Config *config, guint i) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->nameservers->len); + + g_array_remove_index (priv->nameservers, i); +} + guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config) { @@ -594,6 +716,16 @@ nm_ip6_config_add_domain (NMIP6Config *config, const char *domain) g_ptr_array_add (priv->domains, g_strdup (domain)); } +void +nm_ip6_config_del_domain (NMIP6Config *config, guint i) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->domains->len); + + g_ptr_array_remove_index (priv->domains, i); +} + guint32 nm_ip6_config_get_num_domains (NMIP6Config *config) { @@ -636,6 +768,16 @@ nm_ip6_config_add_search (NMIP6Config *config, const char *new) g_ptr_array_add (priv->searches, g_strdup (new)); } +void +nm_ip6_config_del_search (NMIP6Config *config, guint i) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->searches->len); + + g_ptr_array_remove_index (priv->searches, i); +} + guint32 nm_ip6_config_get_num_searches (NMIP6Config *config) { @@ -677,7 +819,11 @@ nm_ip6_config_set_ptp_address (NMIP6Config *config, const struct in6_addr *ptp_a { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - priv->ptp_address = *ptp_address; + if (ptp_address) + priv->ptp_address = *ptp_address; + else + memset (&priv->ptp_address, 0, sizeof (priv->ptp_address)); + } const struct in6_addr * @@ -685,7 +831,7 @@ nm_ip6_config_get_ptp_address (NMIP6Config *config) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - return &priv->ptp_address; + return IN6_IS_ADDR_UNSPECIFIED (&priv->ptp_address) ? NULL : &priv->ptp_address; } /******************************************************************/ diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index ba568cd8c8..cc2a6b96a6 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -63,6 +63,7 @@ void nm_ip6_config_update_setting (NMIP6Config *config, NMSettingIP6Config *sett /* Utility functions */ void nm_ip6_config_merge (NMIP6Config *dst, NMIP6Config *src); +void nm_ip6_config_subtract (NMIP6Config *dst, NMIP6Config *src); int nm_ip6_config_destination_is_direct (NMIP6Config *config, const struct in6_addr *dest, int plen); /* Gateways */ @@ -74,30 +75,35 @@ const struct in6_addr *nm_ip6_config_get_gateway (NMIP6Config *config); /* Addresses */ void nm_ip6_config_reset_addresses (NMIP6Config *config); void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *address); +void nm_ip6_config_del_address (NMIP6Config *config, guint i); guint nm_ip6_config_get_num_addresses (NMIP6Config *config); NMPlatformIP6Address *nm_ip6_config_get_address (NMIP6Config *config, guint i); /* Routes */ void nm_ip6_config_reset_routes (NMIP6Config *config); void nm_ip6_config_add_route (NMIP6Config *config, NMPlatformIP6Route *route); +void nm_ip6_config_del_route (NMIP6Config *config, guint i); guint32 nm_ip6_config_get_num_routes (NMIP6Config *config); NMPlatformIP6Route * nm_ip6_config_get_route (NMIP6Config *config, guint32 i); /* Nameservers */ void nm_ip6_config_reset_nameservers (NMIP6Config *config); void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver); +void nm_ip6_config_del_nameserver (NMIP6Config *config, guint i); guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config); const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, guint i); /* Domains */ void nm_ip6_config_reset_domains (NMIP6Config *config); void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain); +void nm_ip6_config_del_domain (NMIP6Config *config, guint i); guint32 nm_ip6_config_get_num_domains (NMIP6Config *config); const char * nm_ip6_config_get_domain (NMIP6Config *config, guint i); /* Search lists */ void nm_ip6_config_reset_searches (NMIP6Config *config); void nm_ip6_config_add_search (NMIP6Config *config, const char *search); +void nm_ip6_config_del_search (NMIP6Config *config, guint i); guint32 nm_ip6_config_get_num_searches (NMIP6Config *config); const char * nm_ip6_config_get_search (NMIP6Config *config, guint i); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 8a7ecc6781..3e485fdc3d 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -14,7 +14,8 @@ noinst_PROGRAMS = \ test-dhcp-options \ test-policy-hosts \ test-wifi-ap-utils \ - test-ip4-config + test-ip4-config \ + test-ip6-config ####### DHCP options test ####### @@ -53,14 +54,24 @@ test_ip4_config_SOURCES = \ test_ip4_config_LDADD = \ $(top_builddir)/src/libNetworkManager.la +####### ip6 config test ####### + +test_ip6_config_SOURCES = \ + test-ip6-config.c + +test_ip6_config_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + ####### secret agent interface test ####### EXTRA_DIST = test-secret-agent.py ########################################### -check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-config +check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-config test-ip6-config $(abs_builddir)/test-dhcp-options $(abs_builddir)/test-policy-hosts $(abs_builddir)/test-wifi-ap-utils $(abs_builddir)/test-ip4-config + $(abs_builddir)/test-ip6-config + diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c new file mode 100644 index 0000000000..5c3d97805b --- /dev/null +++ b/src/tests/test-ip6-config.c @@ -0,0 +1,176 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + * + */ + +#include +#include +#include + +#include "nm-ip6-config.h" + +static void +addr_init (NMPlatformIP6Address *a, const char *addr, guint plen) +{ + memset (a, 0, sizeof (*a)); + g_assert (inet_pton (AF_INET6, addr, (void *) &a->address) == 1); + a->plen = plen; +} + +static void +route_new (NMPlatformIP6Route *route, const char *network, guint plen, const char *gw) +{ + g_assert (route); + memset (route, 0, sizeof (*route)); + g_assert (inet_pton (AF_INET6, network, (void *) &route->network) == 1); + route->plen = plen; + if (gw) + g_assert (inet_pton (AF_INET6, gw, (void *) &route->gateway) == 1); +} + +static void +addr_to_num (const char *addr, struct in6_addr *out_addr) +{ + memset (out_addr, 0, sizeof (*out_addr)); + g_assert (inet_pton (AF_INET6, addr, (void *) out_addr) == 1); +} + +static NMIP6Config * +build_test_config (void) +{ + NMIP6Config *config; + NMPlatformIP6Address addr; + NMPlatformIP6Route route; + struct in6_addr tmp; + + /* Build up the config to subtract */ + config = nm_ip6_config_new (); + + addr_init (&addr, "abcd:1234:4321::cdde", 64); + nm_ip6_config_add_address (config, &addr); + + route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + nm_ip6_config_add_route (config, &route); + + route_new (&route, "2001:abba::", 16, "2001:abba::2234"); + nm_ip6_config_add_route (config, &route); + + addr_to_num ("3001:abba::3234", &tmp); + nm_ip6_config_set_gateway (config, &tmp); + + addr_to_num ("1:2:3:4::1", &tmp); + nm_ip6_config_add_nameserver (config, &tmp); + addr_to_num ("1:2:3:4::2", &tmp); + nm_ip6_config_add_nameserver (config, &tmp); + nm_ip6_config_add_domain (config, "foobar.com"); + nm_ip6_config_add_domain (config, "baz.com"); + nm_ip6_config_add_search (config, "blahblah.com"); + nm_ip6_config_add_search (config, "beatbox.com"); + + addr_to_num ("1:2:3:4::5", &tmp); + nm_ip6_config_set_ptp_address (config, &tmp); + + return config; +} + +static void +test_subtract (void) +{ + NMIP6Config *src, *dst; + NMPlatformIP6Address addr; + const NMPlatformIP6Address *test_addr; + NMPlatformIP6Route route, *test_route; + const char *expected_addr = "1122:3344:5566::7788"; + guint32 expected_addr_plen = 96; + const char *expected_route_dest = "9991:8882:7773::"; + guint32 expected_route_plen = 24; + const char *expected_route_next_hop = "1119:2228:3337:4446::5555"; + struct in6_addr expected_ns1; + struct in6_addr expected_ns2; + const char *expected_domain = "wonderfalls.com"; + const char *expected_search = "somewhere.com"; + struct in6_addr tmp; + + src = build_test_config (); + + /* add a couple more things to the test config */ + dst = build_test_config (); + addr_init (&addr, expected_addr, expected_addr_plen); + nm_ip6_config_add_address (dst, &addr); + + route_new (&route, expected_route_dest, expected_route_plen, expected_route_next_hop); + nm_ip6_config_add_route (dst, &route); + + addr_to_num ("2222:3333:4444::5555", &expected_ns1); + nm_ip6_config_add_nameserver (dst, &expected_ns1); + addr_to_num ("2222:3333:4444::5556", &expected_ns2); + nm_ip6_config_add_nameserver (dst, &expected_ns2); + + nm_ip6_config_add_domain (dst, expected_domain); + nm_ip6_config_add_search (dst, expected_search); + + nm_ip6_config_subtract (dst, src); + + /* ensure what's left is what we expect */ + g_assert_cmpuint (nm_ip6_config_get_num_addresses (dst), ==, 1); + test_addr = nm_ip6_config_get_address (dst, 0); + g_assert (test_addr != NULL); + addr_to_num (expected_addr, &tmp); + g_assert (memcmp (&test_addr->address, &tmp, sizeof (tmp)) == 0); + g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen); + + g_assert (nm_ip6_config_get_ptp_address (dst) == NULL); + g_assert (nm_ip6_config_get_gateway (dst) == NULL); + + g_assert_cmpuint (nm_ip6_config_get_num_routes (dst), ==, 1); + test_route = nm_ip6_config_get_route (dst, 0); + g_assert (test_route != NULL); + + addr_to_num (expected_route_dest, &tmp); + g_assert (memcmp (&test_route->network, &tmp, sizeof (tmp)) == 0); + g_assert_cmpuint (test_route->plen, ==, expected_route_plen); + addr_to_num (expected_route_next_hop, &tmp); + g_assert (memcmp (&test_route->gateway, &tmp, sizeof (tmp)) == 0); + + g_assert_cmpuint (nm_ip6_config_get_num_nameservers (dst), ==, 2); + g_assert (memcmp (nm_ip6_config_get_nameserver (dst, 0), &expected_ns1, sizeof (expected_ns1)) == 0); + g_assert (memcmp (nm_ip6_config_get_nameserver (dst, 1), &expected_ns2, sizeof (expected_ns2)) == 0); + + g_assert_cmpuint (nm_ip6_config_get_num_domains (dst), ==, 1); + g_assert_cmpstr (nm_ip6_config_get_domain (dst, 0), ==, expected_domain); + g_assert_cmpuint (nm_ip6_config_get_num_searches (dst), ==, 1); + g_assert_cmpstr (nm_ip6_config_get_search (dst, 0), ==, expected_search); + + g_object_unref (src); + g_object_unref (dst); +} + +/*******************************************/ + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_type_init (); + + g_test_add_func ("/ip6-config/subtract", test_subtract); + + return g_test_run (); +} +