diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 9e8a169fd0..35103e54fa 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2310,12 +2310,14 @@ aipd_get_ip4_config (NMDevice *self, guint32 lla) memset (&address, 0, sizeof (address)); address.address = lla; address.plen = 16; + address.source = NM_PLATFORM_SOURCE_IP4LL; nm_ip4_config_add_address (config, &address); /* Add a multicast route for link-local connections: destination= 224.0.0.0, netmask=240.0.0.0 */ memset (&route, 0, sizeof (route)); route.network = htonl (0xE0000000L); route.plen = 4; + route.source = NM_PLATFORM_SOURCE_IP4LL; nm_ip4_config_add_route (config, &route); return config; @@ -2834,6 +2836,7 @@ shared4_new_config (NMDevice *self, NMConnection *connection, NMDeviceStateReaso } config = nm_ip4_config_new (); + address.source = NM_PLATFORM_SOURCE_SHARED; nm_ip4_config_add_address (config, &address); /* Remove the address lock when the object gets disposed */ @@ -3327,6 +3330,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device address.timestamp = discovered_address->timestamp; address.lifetime = discovered_address->lifetime; address.preferred = discovered_address->preferred; + address.source = NM_PLATFORM_SOURCE_RDISC; nm_ip6_config_add_address (priv->ac_ip6_config, &address); } @@ -3349,6 +3353,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device route.network = discovered_route->network; route.plen = discovered_route->plen; route.gateway = discovered_route->gateway; + route.source = NM_PLATFORM_SOURCE_RDISC; nm_ip6_config_add_route (priv->ac_ip6_config, &route); } diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 57298c83ab..b8a9ce30a7 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -866,6 +866,7 @@ ip4_process_dhcpcd_rfc3442_routes (const char *str, route.network = rt_addr; route.plen = rt_cidr; route.gateway = rt_route; + route.source = NM_PLATFORM_SOURCE_DHCP; nm_ip4_config_add_route (ip4_config, &route); } } @@ -968,6 +969,7 @@ ip4_process_dhclient_rfc3442_routes (const char *str, char addr[INET_ADDRSTRLEN]; /* normal route */ + route.source = NM_PLATFORM_SOURCE_DHCP; nm_ip4_config_add_route (ip4_config, &route); nm_log_info (LOGD_DHCP4, " classless static route %s/%d gw %s", @@ -1087,6 +1089,7 @@ process_classful_routes (GHashTable *options, NMIP4Config *ip4_config) route.plen = 32; } route.gateway = rt_route; + route.source = NM_PLATFORM_SOURCE_DHCP; nm_ip4_config_add_route (ip4_config, &route); nm_log_info (LOGD_DHCP, " static route %s", @@ -1252,6 +1255,7 @@ ip4_options_to_config (NMDHCPClient *self) nm_log_info (LOGD_DHCP4, " lease time %d", address.lifetime); } + address.source = NM_PLATFORM_SOURCE_DHCP; nm_ip4_config_add_address (ip4_config, &address); str = g_hash_table_lookup (priv->options, "new_host_name"); @@ -1419,6 +1423,7 @@ ip6_options_to_config (NMDHCPClient *self) } address.address = tmp_addr; + address.source = NM_PLATFORM_SOURCE_DHCP; nm_ip6_config_add_address (ip6_config, &address); nm_log_info (LOGD_DHCP6, " address %s", str); } else if (priv->info_only == FALSE) { diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c index 64e8f72669..fad3a7a8bb 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c +++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c @@ -625,6 +625,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, address.plen = nm_utils_ip4_get_default_prefix (address.address); address.lifetime = address.preferred = expiry; + address.source = NM_PLATFORM_SOURCE_DHCP; ip4 = nm_ip4_config_new (); nm_ip4_config_add_address (ip4, &address); diff --git a/src/modem-manager/nm-modem-broadband.c b/src/modem-manager/nm-modem-broadband.c index 508624d8e4..032557de99 100644 --- a/src/modem-manager/nm-modem-broadband.c +++ b/src/modem-manager/nm-modem-broadband.c @@ -656,6 +656,7 @@ static_stage3_done (NMModemBroadband *self) memset (&address, 0, sizeof (address)); address.address = address_network; address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config); + address.source = NM_PLATFORM_SOURCE_WWAN; nm_ip4_config_add_address (config, &address); nm_log_info (LOGD_MB, " address %s/%d", diff --git a/src/modem-manager/nm-modem-old.c b/src/modem-manager/nm-modem-old.c index 60ddd4732d..866a94a122 100644 --- a/src/modem-manager/nm-modem-old.c +++ b/src/modem-manager/nm-modem-old.c @@ -620,6 +620,7 @@ static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) /* IP address */ address.address = g_value_get_uint (g_value_array_get_nth (ret_array, 0)); address.plen = 32; + address.source = NM_PLATFORM_SOURCE_WWAN; nm_ip4_config_add_address (config, &address); nm_log_info (LOGD_MB, " address %s/%d", diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index b9ce0cbadb..ff544cc535 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -335,6 +335,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting) address.plen = nm_ip4_address_get_prefix (s_addr); address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT; address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; + address.source = NM_PLATFORM_SOURCE_USER; nm_ip4_config_add_address (config, &address); } @@ -351,6 +352,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting) route.plen = nm_ip4_route_get_prefix (s_route); route.gateway = nm_ip4_route_get_next_hop (s_route); route.metric = nm_ip4_route_get_metric (s_route); + route.source = NM_PLATFORM_SOURCE_USER; nm_ip4_config_add_route (config, &route); } @@ -981,10 +983,21 @@ nm_ip4_config_reset_addresses (NMIP4Config *config) } } +/** + * nm_ip4_config_add_address: + * @config: the #NMIP4Config + * @new: the new address to add to @config + * + * Adds the new address to @config. If an address with the same basic properties + * (address, prefix) already exists in @config, it is overwritten with the + * lifetime and preferred of @new. The source is also overwritten by the source + * from @new if that source is higher priority. + */ void nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMPlatformSource old_source; int i; g_return_if_fail (new != NULL); @@ -995,7 +1008,10 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) if (addresses_are_duplicate (item, new, FALSE)) { if (nm_platform_ip4_address_cmp (item, new) == 0) return; + old_source = item->source; memcpy (item, new, sizeof (*item)); + /* Restore highest priority source */ + item->source = MAX (old_source, new->source); goto NOTIFY; } } @@ -1061,10 +1077,21 @@ nm_ip4_config_reset_routes (NMIP4Config *config) } } +/** + * nm_ip4_config_add_route: + * @config: the #NMIP4Config + * @new: the new route to add to @config + * + * Adds the new route to @config. If a route with the same basic properties + * (network, prefix) already exists in @config, it is overwritten including the + * gateway and metric of @new. The source is also overwritten by the source + * from @new if that source is higher priority. + */ void nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMPlatformSource old_source; int i; g_return_if_fail (new != NULL); @@ -1075,7 +1102,10 @@ nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new) if (routes_are_duplicate (item, new, FALSE)) { if (nm_platform_ip4_route_cmp (item, new) == 0) return; + old_source = item->source; memcpy (item, new, sizeof (*item)); + /* Restore highest priority source */ + item->source = MAX (old_source, new->source); goto NOTIFY; } } @@ -1500,6 +1530,19 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only } } +/** + * nm_ip4_config_equal: + * @a: first config to compare + * @b: second config to compare + * + * Compares two #NMIP4Configs for basic equality. This means that all + * attributes must exist in the same order in both configs (addresses, routes, + * domains, DNS servers, etc) but some attributes (address lifetimes, and address + * and route sources) are ignored. + * + * Returns: %TRUE if the configurations are basically equal to each other, + * %FALSE if not + */ gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b) { diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 178f0b51b1..64cdbd44e0 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -330,6 +330,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting) address.plen = nm_ip6_address_get_prefix (s_addr); address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT; address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; + address.source = NM_PLATFORM_SOURCE_USER; nm_ip6_config_add_address (config, &address); } @@ -346,6 +347,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting) route.plen = nm_ip6_route_get_prefix (s_route); route.gateway = *nm_ip6_route_get_next_hop (s_route); route.metric = nm_ip6_route_get_metric (s_route); + route.source = NM_PLATFORM_SOURCE_USER; nm_ip6_config_add_route (config, &route); } @@ -887,10 +889,21 @@ nm_ip6_config_reset_addresses (NMIP6Config *config) } } +/** + * nm_ip6_config_add_address: + * @config: the #NMIP6Config + * @new: the new address to add to @config + * + * Adds the new address to @config. If an address with the same basic properties + * (address, prefix) already exists in @config, it is overwritten with the + * lifetime and preferred of @new. The source is also overwritten by the source + * from @new if that source is higher priority. + */ void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMPlatformSource old_source; int i; g_return_if_fail (new != NULL); @@ -901,8 +914,11 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { if (nm_platform_ip6_address_cmp (item, new) == 0) return; + old_source = item->source; /* Copy over old item to get new lifetime, timestamp, preferred */ *item = *new; + /* But restore highest priority source */ + item->source = MAX (old_source, new->source); goto NOTIFY; } } @@ -969,10 +985,21 @@ nm_ip6_config_reset_routes (NMIP6Config *config) } } +/** + * nm_ip6_config_add_route: + * @config: the #NMIP6Config + * @new: the new route to add to @config + * + * Adds the new route to @config. If a route with the same basic properties + * (network, prefix) already exists in @config, it is overwritten including the + * gateway and metric of @new. The source is also overwritten by the source + * from @new if that source is higher priority. + */ void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMPlatformSource old_source; int i; g_return_if_fail (new != NULL); @@ -983,7 +1010,10 @@ nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new) if (routes_are_duplicate (item, new, FALSE)) { if (nm_platform_ip6_route_cmp (item, new) == 0) return; + old_source = item->source; *item = *new; + /* Restore highest priority source */ + item->source = MAX (old_source, new->source); goto NOTIFY; } } @@ -1268,6 +1298,19 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only } } +/** + * nm_ip6_config_equal: + * @a: first config to compare + * @b: second config to compare + * + * Compares two #NMIP6Configs for basic equality. This means that all + * attributes must exist in the same order in both configs (addresses, routes, + * domains, DNS servers, etc) but some attributes (address lifetimes, and address + * and route sources) are ignored. + * + * Returns: %TRUE if the configurations are basically equal to each other, + * %FALSE if not + */ gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b) { diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 8e85c59262..fd476c4103 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2196,6 +2196,7 @@ ip4_address_get_all (NMPlatform *platform, int ifindex) for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) { if (nl_object_is_marked (object)) { init_ip4_address (&address, (struct rtnl_addr *) object); + address.source = NM_PLATFORM_SOURCE_KERNEL; g_array_append_val (addresses, address); nl_object_unmark (object); } @@ -2219,6 +2220,7 @@ ip6_address_get_all (NMPlatform *platform, int ifindex) for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) { if (nl_object_is_marked (object)) { init_ip6_address (&address, (struct rtnl_addr *) object); + address.source = NM_PLATFORM_SOURCE_KERNEL; g_array_append_val (addresses, address); nl_object_unmark (object); } @@ -2410,6 +2412,7 @@ ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default) for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) { if (nl_object_is_marked (object)) { if (init_ip4_route (&route, (struct rtnl_route *) object)) { + route.source = NM_PLATFORM_SOURCE_KERNEL; if (route.plen != 0 || include_default) g_array_append_val (routes, route); } @@ -2435,6 +2438,7 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default) for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) { if (nl_object_is_marked (object)) { if (init_ip6_route (&route, (struct rtnl_route *) object)) { + route.source = NM_PLATFORM_SOURCE_KERNEL; if (route.plen != 0 || include_default) g_array_append_val (routes, route); } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 9a40d6770f..600db99d2a 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1563,9 +1563,15 @@ array_contains_ip4_route (const GArray *routes, const NMPlatformIP4Route *route) guint len = routes ? routes->len : 0; guint i; - for (i = 0; i < len; i++) - if (!memcmp (&g_array_index (routes, NMPlatformIP4Route, i), route, sizeof (*route))) + for (i = 0; i < len; i++) { + NMPlatformIP4Route *c = &g_array_index (routes, NMPlatformIP4Route, i); + + if (route->network == c->network && + route->plen == c->plen && + route->gateway == c->gateway && + route->metric == c->metric) return TRUE; + } return FALSE; } @@ -1576,9 +1582,15 @@ array_contains_ip6_route (const GArray *routes, const NMPlatformIP6Route *route) guint len = routes ? routes->len : 0; guint i; - for (i = 0; i < len; i++) - if (!memcmp (&g_array_index (routes, NMPlatformIP6Route, i), route, sizeof (*route))) + for (i = 0; i < len; i++) { + NMPlatformIP6Route *c = &g_array_index (routes, NMPlatformIP6Route, i); + + if (IN6_ARE_ADDR_EQUAL (&route->network, &c->network) && + route->plen == c->plen && + IN6_ARE_ADDR_EQUAL (&route->gateway, &c->gateway) && + route->metric == c->metric) return TRUE; + } return FALSE; } @@ -1606,7 +1618,6 @@ nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes) routes = nm_platform_ip4_route_get_all (ifindex, FALSE); for (i = 0; i < routes->len; i++) { route = &g_array_index (routes, NMPlatformIP4Route, i); - route->ifindex = 0; if (!array_contains_ip4_route (known_routes, route)) nm_platform_ip4_route_delete (ifindex, route->network, route->plen, route->metric); @@ -1684,6 +1695,34 @@ nm_platform_route_flush (int ifindex) /******************************************************************/ +static const char * +source_to_string (NMPlatformSource source) +{ + switch (source) { + case NM_PLATFORM_SOURCE_KERNEL: + return "kernel"; + case NM_PLATFORM_SOURCE_SHARED: + return "shared"; + case NM_PLATFORM_SOURCE_IP4LL: + return "ipv4ll"; + case NM_PLATFORM_SOURCE_PPP: + return "ppp"; + case NM_PLATFORM_SOURCE_WWAN: + return "wwan"; + case NM_PLATFORM_SOURCE_VPN: + return "vpn"; + case NM_PLATFORM_SOURCE_DHCP: + return "dhcp"; + case NM_PLATFORM_SOURCE_RDISC: + return "rdisc"; + case NM_PLATFORM_SOURCE_USER: + return "user"; + default: + break; + } + return "unknown"; +} + /** * nm_platform_ip4_address_to_string: * @route: pointer to NMPlatformIP4Address address structure @@ -1718,11 +1757,12 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address) s_dev = address->ifindex > 0 ? nm_platform_link_get_name (address->ifindex) : NULL; str_dev = s_dev ? g_strconcat (" dev ", s_dev, NULL) : NULL; - g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s", + g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s src %s", s_address, address->plen, (guint)address->lifetime, (guint)address->preferred, (guint)address->timestamp, str_peer ? str_peer : "", - str_dev ? str_dev : ""); + str_dev ? str_dev : "", + source_to_string (address->source)); g_free (str_dev); g_free (str_peer); return buffer; @@ -1767,12 +1807,13 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) rtnl_addr_flags2str(address->flags, s_flags, sizeof(s_flags)); str_flags = s_flags[0] ? g_strconcat (" flags ", s_flags, NULL) : NULL; - g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s%s", + g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s%s src %s", s_address, address->plen, (guint)address->lifetime, (guint)address->preferred, (guint)address->timestamp, str_peer ? str_peer : "", str_dev ? str_dev : "", - str_flags ? str_flags : ""); + str_flags ? str_flags : "", + source_to_string (address->source)); g_free (str_flags); g_free (str_dev); g_free (str_peer); @@ -1807,10 +1848,11 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route) s_dev = route->ifindex > 0 ? nm_platform_link_get_name (route->ifindex) : NULL; str_dev = s_dev ? g_strconcat (" dev ", s_dev, NULL) : NULL; - g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u", + g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u src %s", s_network, route->plen, s_gateway, str_dev ? str_dev : "", - route->metric, route->mss); + route->metric, route->mss, + source_to_string (route->source)); g_free (str_dev); return buffer; } @@ -1843,10 +1885,11 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) s_dev = route->ifindex > 0 ? nm_platform_link_get_name (route->ifindex) : NULL; str_dev = s_dev ? g_strconcat (" dev ", s_dev, NULL) : NULL; - g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u", + g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u src %s", s_network, route->plen, s_gateway, str_dev ? str_dev : "", - route->metric, route->mss); + route->metric, route->mss, + source_to_string (route->source)); g_free (str_dev); return buffer; } @@ -1879,9 +1922,10 @@ int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) { _CMP_POINTER (a, b); + _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, address); _CMP_FIELD_MEMCMP (a, b, peer_address); - _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, timestamp); _CMP_FIELD (a, b, lifetime); @@ -1894,6 +1938,7 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A { _CMP_POINTER (a, b); _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, address); _CMP_FIELD_MEMCMP (a, b, peer_address); _CMP_FIELD (a, b, plen); @@ -1909,6 +1954,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route { _CMP_POINTER (a, b); _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, network); _CMP_FIELD (a, b, plen); _CMP_FIELD_MEMCMP (a, b, gateway); @@ -1922,6 +1968,7 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route { _CMP_POINTER (a, b); _CMP_FIELD (a, b, ifindex); + _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, network); _CMP_FIELD (a, b, plen); _CMP_FIELD_MEMCMP (a, b, gateway); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 0a5a599898..cbda607f03 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -119,8 +119,23 @@ typedef struct { #define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32 +typedef enum { + /* In priority order; higher number == higher priority */ + NM_PLATFORM_SOURCE_UNKNOWN, + NM_PLATFORM_SOURCE_KERNEL, + NM_PLATFORM_SOURCE_SHARED, + NM_PLATFORM_SOURCE_IP4LL, + NM_PLATFORM_SOURCE_PPP, + NM_PLATFORM_SOURCE_WWAN, + NM_PLATFORM_SOURCE_VPN, + NM_PLATFORM_SOURCE_DHCP, + NM_PLATFORM_SOURCE_RDISC, + NM_PLATFORM_SOURCE_USER, +} NMPlatformSource; + typedef struct { int ifindex; + NMPlatformSource source; in_addr_t address; in_addr_t peer_address; /* PTP peer address */ int plen; @@ -131,6 +146,7 @@ typedef struct { typedef struct { int ifindex; + NMPlatformSource source; struct in6_addr address; struct in6_addr peer_address; int plen; @@ -142,6 +158,7 @@ typedef struct { typedef struct { int ifindex; + NMPlatformSource source; in_addr_t network; int plen; in_addr_t gateway; @@ -151,6 +168,7 @@ typedef struct { typedef struct { int ifindex; + NMPlatformSource source; struct in6_addr network; int plen; struct in6_addr gateway; diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c index 7b8493716e..cf085a8a73 100644 --- a/src/ppp-manager/nm-ppp-manager.c +++ b/src/ppp-manager/nm-ppp-manager.c @@ -550,6 +550,7 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager, address.plen = g_value_get_uint (val); if (address.address && address.plen) { + address.source = NM_PLATFORM_SOURCE_PPP; nm_ip4_config_add_address (config, &address); } else { nm_log_err (LOGD_PPP, "invalid IPv4 address received!"); diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index fde4a40cf2..e2d56948b3 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -173,6 +173,119 @@ test_subtract (void) g_object_unref (dst); } +static void +test_compare_with_source (void) +{ + NMIP4Config *a, *b; + NMPlatformIP4Address addr; + NMPlatformIP4Route route; + + a = nm_ip4_config_new (); + b = nm_ip4_config_new (); + + /* Address */ + addr_init (&addr, "1.2.3.4", NULL, 24); + addr.source = NM_PLATFORM_SOURCE_USER; + nm_ip4_config_add_address (a, &addr); + + addr.source = NM_PLATFORM_SOURCE_VPN; + nm_ip4_config_add_address (b, &addr); + + /* Route */ + route_new (&route, "10.0.0.0", 8, "192.168.1.1"); + route.source = NM_PLATFORM_SOURCE_USER; + nm_ip4_config_add_route (a, &route); + + route.source = NM_PLATFORM_SOURCE_VPN; + nm_ip4_config_add_route (b, &route); + + /* Assert that the configs are basically the same, eg that the source is ignored */ + g_assert (nm_ip4_config_equal (a, b)); + + g_object_unref (a); + g_object_unref (b); +} + +static void +test_add_address_with_source (void) +{ + NMIP4Config *a; + NMPlatformIP4Address addr; + const NMPlatformIP4Address *test_addr; + + a = nm_ip4_config_new (); + + /* Test that a higher priority source is not overwritten */ + addr_init (&addr, "1.2.3.4", NULL, 24); + addr.source = NM_PLATFORM_SOURCE_USER; + nm_ip4_config_add_address (a, &addr); + + test_addr = nm_ip4_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER); + + addr.source = NM_PLATFORM_SOURCE_VPN; + nm_ip4_config_add_address (a, &addr); + + test_addr = nm_ip4_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER); + + /* Test that a lower priority address source is overwritten */ + nm_ip4_config_del_address (a, 0); + addr.source = NM_PLATFORM_SOURCE_KERNEL; + nm_ip4_config_add_address (a, &addr); + + test_addr = nm_ip4_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_KERNEL); + + addr.source = NM_PLATFORM_SOURCE_USER; + nm_ip4_config_add_address (a, &addr); + + test_addr = nm_ip4_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER); + + g_object_unref (a); +} + +static void +test_add_route_with_source (void) +{ + NMIP4Config *a; + NMPlatformIP4Route route; + const NMPlatformIP4Route *test_route; + + a = nm_ip4_config_new (); + + /* Test that a higher priority source is not overwritten */ + route_new (&route, "1.2.3.4", 24, "1.2.3.1"); + route.source = NM_PLATFORM_SOURCE_USER; + nm_ip4_config_add_route (a, &route); + + test_route = nm_ip4_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER); + + route.source = NM_PLATFORM_SOURCE_VPN; + nm_ip4_config_add_route (a, &route); + + test_route = nm_ip4_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER); + + /* Test that a lower priority address source is overwritten */ + nm_ip4_config_del_route (a, 0); + route.source = NM_PLATFORM_SOURCE_KERNEL; + nm_ip4_config_add_route (a, &route); + + test_route = nm_ip4_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_KERNEL); + + route.source = NM_PLATFORM_SOURCE_USER; + nm_ip4_config_add_route (a, &route); + + test_route = nm_ip4_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER); + + g_object_unref (a); +} + /*******************************************/ int @@ -183,6 +296,9 @@ main (int argc, char **argv) g_type_init (); g_test_add_func ("/ip4-config/subtract", test_subtract); + g_test_add_func ("/ip4-config/compare-with-source", test_compare_with_source); + g_test_add_func ("/ip4-config/add-address-with-source", test_add_address_with_source); + g_test_add_func ("/ip4-config/add-route-with-source", test_add_route_with_source); return g_test_run (); } diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index b8b9c7b9ea..c79ac20a17 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -160,6 +160,119 @@ test_subtract (void) g_object_unref (dst); } +static void +test_compare_with_source (void) +{ + NMIP6Config *a, *b; + NMPlatformIP6Address addr; + NMPlatformIP6Route route; + + a = nm_ip6_config_new (); + b = nm_ip6_config_new (); + + /* Address */ + addr_init (&addr, "1122:3344:5566::7788", NULL, 64); + addr.source = NM_PLATFORM_SOURCE_USER; + nm_ip6_config_add_address (a, &addr); + + addr.source = NM_PLATFORM_SOURCE_VPN; + nm_ip6_config_add_address (b, &addr); + + /* Route */ + route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route.source = NM_PLATFORM_SOURCE_USER; + nm_ip6_config_add_route (a, &route); + + route.source = NM_PLATFORM_SOURCE_VPN; + nm_ip6_config_add_route (b, &route); + + /* Assert that the configs are basically the same, eg that the source is ignored */ + g_assert (nm_ip6_config_equal (a, b)); + + g_object_unref (a); + g_object_unref (b); +} + +static void +test_add_address_with_source (void) +{ + NMIP6Config *a; + NMPlatformIP6Address addr; + const NMPlatformIP6Address *test_addr; + + a = nm_ip6_config_new (); + + /* Test that a higher priority source is not overwritten */ + addr_init (&addr, "1122:3344:5566::7788", NULL, 64); + addr.source = NM_PLATFORM_SOURCE_USER; + nm_ip6_config_add_address (a, &addr); + + test_addr = nm_ip6_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER); + + addr.source = NM_PLATFORM_SOURCE_VPN; + nm_ip6_config_add_address (a, &addr); + + test_addr = nm_ip6_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER); + + /* Test that a lower priority address source is overwritten */ + nm_ip6_config_del_address (a, 0); + addr.source = NM_PLATFORM_SOURCE_KERNEL; + nm_ip6_config_add_address (a, &addr); + + test_addr = nm_ip6_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_KERNEL); + + addr.source = NM_PLATFORM_SOURCE_USER; + nm_ip6_config_add_address (a, &addr); + + test_addr = nm_ip6_config_get_address (a, 0); + g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER); + + g_object_unref (a); +} + +static void +test_add_route_with_source (void) +{ + NMIP6Config *a; + NMPlatformIP6Route route; + const NMPlatformIP6Route *test_route; + + a = nm_ip6_config_new (); + + /* Test that a higher priority source is not overwritten */ + route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route.source = NM_PLATFORM_SOURCE_USER; + nm_ip6_config_add_route (a, &route); + + test_route = nm_ip6_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER); + + route.source = NM_PLATFORM_SOURCE_VPN; + nm_ip6_config_add_route (a, &route); + + test_route = nm_ip6_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER); + + /* Test that a lower priority address source is overwritten */ + nm_ip6_config_del_route (a, 0); + route.source = NM_PLATFORM_SOURCE_KERNEL; + nm_ip6_config_add_route (a, &route); + + test_route = nm_ip6_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_KERNEL); + + route.source = NM_PLATFORM_SOURCE_USER; + nm_ip6_config_add_route (a, &route); + + test_route = nm_ip6_config_get_route (a, 0); + g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER); + + g_object_unref (a); +} + /*******************************************/ int @@ -170,6 +283,9 @@ main (int argc, char **argv) g_type_init (); g_test_add_func ("/ip6-config/subtract", test_subtract); + g_test_add_func ("/ip6-config/compare-with-source", test_compare_with_source); + g_test_add_func ("/ip6-config/add-address-with-source", test_add_address_with_source); + g_test_add_func ("/ip6-config/add-route-with-source", test_add_route_with_source); return g_test_run (); } diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index f1d7d46d48..b0d71916ef 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -333,6 +333,7 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32 if (nm_ip4_config_destination_is_direct (parent_config, vpn_gw, 32)) route.gateway = 0; + route.source = NM_PLATFORM_SOURCE_VPN; nm_ip4_config_add_route (config, &route); /* Ensure there's a route to the parent device's gateway through the @@ -343,6 +344,7 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32 memset (&route, 0, sizeof (route)); route.network = parent_gw; route.plen = 32; + route.source = NM_PLATFORM_SOURCE_VPN; nm_ip4_config_add_route (config, &route); } @@ -378,6 +380,7 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, if (nm_ip6_config_destination_is_direct (parent_config, vpn_gw, 128)) route.gateway = in6addr_any; + route.source = NM_PLATFORM_SOURCE_VPN; nm_ip6_config_add_route (config, &route); /* Ensure there's a route to the parent device's gateway through the @@ -388,6 +391,7 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, memset (&route, 0, sizeof (route)); route.network = *parent_gw; route.plen = 128; + route.source = NM_PLATFORM_SOURCE_VPN; nm_ip6_config_add_route (config, &route); } @@ -944,6 +948,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, address.plen = g_value_get_uint (val); if (address.address && address.plen) { + address.source = NM_PLATFORM_SOURCE_VPN; nm_ip4_config_add_address (config, &address); } else { nm_log_err (LOGD_VPN, "invalid IP4 config received!"); @@ -1002,6 +1007,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, route.network = nm_ip4_route_get_dest (item); route.plen = nm_ip4_route_get_prefix (item); route.gateway = nm_ip4_route_get_next_hop (item); + route.source = NM_PLATFORM_SOURCE_VPN; /* Ignore host routes to the VPN gateway since NM adds one itself * below. Since NM knows more about the routing situation than @@ -1094,9 +1100,10 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy, if (val) address.plen = g_value_get_uint (val); - if (!IN6_IS_ADDR_UNSPECIFIED (&address.address) && address.plen) + if (!IN6_IS_ADDR_UNSPECIFIED (&address.address) && address.plen) { + address.source = NM_PLATFORM_SOURCE_VPN; nm_ip6_config_add_address (config, &address); - else { + } else { nm_log_err (LOGD_VPN, "invalid IP6 config received!"); g_object_unref (config); nm_vpn_connection_config_maybe_complete (connection, FALSE); @@ -1145,6 +1152,7 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy, route.network = *nm_ip6_route_get_dest (item); route.plen = nm_ip6_route_get_prefix (item); route.gateway = *nm_ip6_route_get_next_hop (item); + route.source = NM_PLATFORM_SOURCE_VPN; /* Ignore host routes to the VPN gateway since NM adds one itself * below. Since NM knows more about the routing situation than