From 786ab294dbe317b66c4103b10bbebc22ff3f4461 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 10 Jun 2021 22:45:48 +0200 Subject: [PATCH 1/4] libnm-platform: add nm_platform_ip_address_match() Replace nm_platform_ip6_address_match() with a version generic for IPv4 and IPv6. (cherry picked from commit 376c7f83152ebd561ba837695dd24b641ad38021) --- src/core/nm-ip6-config.c | 2 +- src/libnm-platform/nm-platform.c | 30 +++++++++++++++++++++--------- src/libnm-platform/nm-platform.h | 5 +++-- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c index 8793c1c27a..61dccf3b0f 100644 --- a/src/core/nm-ip6-config.c +++ b/src/core/nm-ip6-config.c @@ -1644,7 +1644,7 @@ nm_ip6_config_find_first_address(const NMIP6Config *self, NMPlatformMatchFlags m nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { - if (nm_platform_ip6_address_match(addr, match_flag)) + if (nm_platform_ip_address_match(AF_INET6, (NMPlatformIPAddress *) addr, match_flag)) return addr; } return NULL; diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 2af6cbb3c9..98c8733653 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -3413,7 +3413,9 @@ nm_platform_ip6_address_get_peer(const NMPlatformIP6Address *addr) } gboolean -nm_platform_ip6_address_match(const NMPlatformIP6Address *addr, NMPlatformMatchFlags match_flag) +nm_platform_ip_address_match(int addr_family, + const NMPlatformIPAddress *address, + NMPlatformMatchFlags match_flag) { nm_assert(!NM_FLAGS_ANY( match_flag, @@ -3421,19 +3423,29 @@ nm_platform_ip6_address_match(const NMPlatformIP6Address *addr, NMPlatformMatchF nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); - if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) - return FALSE; + if (addr_family == AF_INET) { + if (nm_utils_ip4_address_is_link_local(((NMPlatformIP4Address *) address)->address)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) + return FALSE; + } else { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) + return FALSE; + } } else { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) - return FALSE; + if (IN6_IS_ADDR_LINKLOCAL(address->address_ptr)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) + return FALSE; + } else { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) + return FALSE; + } } - if (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_DADFAILED)) { + if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_DADFAILED)) { if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) return FALSE; - } else if (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { + } else if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_TENTATIVE) + && !NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_OPTIMISTIC)) { if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) return FALSE; } else { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 4f76e19b90..096851b160 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -2380,7 +2380,8 @@ struct _NMDedupMultiIndex *nm_platform_get_multi_idx(NMPlatform *self); /*****************************************************************************/ -gboolean nm_platform_ip6_address_match(const NMPlatformIP6Address *addr, - NMPlatformMatchFlags match_flag); +gboolean nm_platform_ip_address_match(int addr_family, + const NMPlatformIPAddress *addr, + NMPlatformMatchFlags match_flag); #endif /* __NETWORKMANAGER_PLATFORM_H__ */ From a3a282677bfb1f761a658bcfb98bb9fd71e264f8 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 10 Jun 2021 22:48:43 +0200 Subject: [PATCH 2/4] core: add nm_ip_config_find_first_address() Replace nm_ip6_config_find_first_address() with a version generic for IPv4 and IPv6. (cherry picked from commit ca31cbbc7478230b35aa0fd7acfccd09aa1572fc) --- src/core/devices/nm-device.c | 32 ++++++++++++++++---------------- src/core/nm-ip4-config.c | 20 ++++++++++++++++++++ src/core/nm-ip4-config.h | 3 +++ src/core/nm-ip6-config.c | 22 ---------------------- src/core/nm-ip6-config.h | 2 -- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 19a46b5f52..d6110d04ec 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -9893,9 +9893,9 @@ dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) nm_assert(s_con); if (priv->ext_ip6_config_captured) { - ll_addr = nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); + ll_addr = nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); } if (!ll_addr) { @@ -10134,9 +10134,9 @@ linklocal6_check_complete(NMDevice *self) } if (!priv->ext_ip6_config_captured - || !nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { + || !nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { /* we don't have a non-tentative link local address yet. Wait longer. */ return; } @@ -10182,10 +10182,10 @@ check_and_add_ipv6ll_addr(NMDevice *self) return; if (priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { + && nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { /* Already have an LL address, nothing to do */ return; } @@ -10255,9 +10255,9 @@ linklocal6_start(NMDevice *self) nm_clear_g_source(&priv->linklocal6_timeout_id); if (priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) + && nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) return TRUE; _LOGD(LOGD_DEVICE, @@ -10836,9 +10836,9 @@ ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self) * addresses we find inside priv->ip_config_6. */ if (priv->ip_config_6 - && nm_ip6_config_find_first_address(priv->ip_config_6, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) + && nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ip_config_6), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); else nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); diff --git a/src/core/nm-ip4-config.c b/src/core/nm-ip4-config.c index 171ed4bae1..47f0ee3a80 100644 --- a/src/core/nm-ip4-config.c +++ b/src/core/nm-ip4-config.c @@ -1977,6 +1977,26 @@ nm_ip_config_dump(const NMIPConfig *self, const char *detail, NMLogLevel level, /*****************************************************************************/ +gconstpointer +nm_ip_config_find_first_address(const NMIPConfig *self, NMPlatformMatchFlags match_flag) +{ + NMDedupMultiIter iter; + const NMPlatformIPAddress *address; + + g_return_val_if_fail(NM_IS_IP_CONFIG(self), NULL); + + nm_assert(!NM_FLAGS_ANY( + match_flag, + ~(NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); + + nm_ip_config_iter_ip_address_for_each (&iter, self, &address) { + if (nm_platform_ip_address_match(nm_ip_config_get_addr_family(self), address, match_flag)) + return address; + } + + return NULL; +} + void nm_ip4_config_reset_addresses(NMIP4Config *self) { diff --git a/src/core/nm-ip4-config.h b/src/core/nm-ip4-config.h index 7032a2385e..fdaa6d4673 100644 --- a/src/core/nm-ip4-config.h +++ b/src/core/nm-ip4-config.h @@ -664,4 +664,7 @@ nm_ip_config_intersect_alloc(const NMIPConfig *a, } } +gconstpointer nm_ip_config_find_first_address(const NMIPConfig * self, + NMPlatformMatchFlags match_flag); + #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c index 61dccf3b0f..d2ecf1759b 100644 --- a/src/core/nm-ip6-config.c +++ b/src/core/nm-ip6-config.c @@ -1628,28 +1628,6 @@ nm_ip6_config_lookup_address(const NMIP6Config *self, const struct in6_addr *add return entry ? NMP_OBJECT_CAST_IP6_ADDRESS(entry->obj) : NULL; } -const NMPlatformIP6Address * -nm_ip6_config_find_first_address(const NMIP6Config *self, NMPlatformMatchFlags match_flag) -{ - const NMPlatformIP6Address *addr; - NMDedupMultiIter iter; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(self), NULL); - - nm_assert(!NM_FLAGS_ANY( - match_flag, - ~(NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); - - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); - - nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { - if (nm_platform_ip_address_match(AF_INET6, (NMPlatformIPAddress *) addr, match_flag)) - return addr; - } - return NULL; -} - /** * nm_ip6_config_has_dad_pending_addresses * @self: configuration containing the addresses to check diff --git a/src/core/nm-ip6-config.h b/src/core/nm-ip6-config.h index 4aa0ee4e58..8694ab0c0f 100644 --- a/src/core/nm-ip6-config.h +++ b/src/core/nm-ip6-config.h @@ -125,8 +125,6 @@ void _nmtst_ip6_config_del_address(NMIP6Config *self, guint i); guint nm_ip6_config_get_num_addresses(const NMIP6Config *self); const NMPlatformIP6Address *nm_ip6_config_get_first_address(const NMIP6Config *self); const NMPlatformIP6Address *_nmtst_ip6_config_get_address(const NMIP6Config *self, guint i); -const NMPlatformIP6Address *nm_ip6_config_find_first_address(const NMIP6Config * self, - NMPlatformMatchFlags match_flag); gboolean nm_ip6_config_address_exists(const NMIP6Config *self, const NMPlatformIP6Address *address); const NMPlatformIP6Address *nm_ip6_config_lookup_address(const NMIP6Config * self, const struct in6_addr *addr); From 2ca56c9bbdb1447004873cddccb70625ea722d23 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 10 Jun 2021 22:53:31 +0200 Subject: [PATCH 3/4] libnm-platform: add NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED Add a new flag to match deprecated addresses. An address is deprecated when its preferred lifetime has expired but its valid lifetime has not. Address deprecation is one of the criteria for source address selection in IPv6. For IPv4 the deprecation doesn't have any real effect. Note that this commit changes the behavior of nm_ip_config_get_first_address(WITH_ADDRSTATE_NORMAL), since now deprecated addresses are not returned. However this should not impact existing callers since they either: - request a IPv6 (WITH_ADDRTYPE_LINKLOCAL | WITH_ADDRSTATE_NORMAL) address; IPv6 link-local addresses are supposed to have infinite lifetimes; or - request a IPv6 (WITH_ADDRTYPE_NORMAL | WITH_ADDRSTATE__ANY) address. (cherry picked from commit ff84a4736d5b9f075105723fa9add14255b3189a) --- src/libnm-platform/nm-platform.c | 3 +++ src/libnm-platform/nm-platform.h | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 98c8733653..089d0d42c1 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -3448,6 +3448,9 @@ nm_platform_ip_address_match(int addr_family, && !NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_OPTIMISTIC)) { if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) return FALSE; + } else if (NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_DEPRECATED)) { + if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED)) + return FALSE; } else { if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) return FALSE; diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 096851b160..e627917698 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -176,12 +176,13 @@ typedef enum { NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL, - NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), - NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED, + NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), + NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED = (1LL << 5), + NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = + NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED, } NMPlatformMatchFlags; #define NM_PLATFORM_LINK_OTHER_NETNS (-1) From c8c7e8320b253daedb45756cc1ed7d1956a33d9e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 10 Jun 2021 22:56:02 +0200 Subject: [PATCH 4/4] device: prefer IPv6 not-deprecated addresses for hostname lookup In presence of a IPv6 deprecated address and a non-deprecated one, the latter will be used by kernel for new connections according to RFC 6724 section 5 (Source Address Selection). Prefer it also to lookup a hostname via reverse DNS. While at it, also prefer non-link-local addresses over link-local ones. (cherry picked from commit 3c55db886a6062010450fd67645815e567b03bbf) --- src/core/devices/nm-device.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index d6110d04ec..269418df40 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -17799,13 +17799,36 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean priv->hostname_resolver_x[IS_IPv4] = resolver; } - /* Determine the first address of the interface and - * whether it changed from the previous lookup */ + /* Determine the most suitable address of the interface + * and whether it changed from the previous lookup */ ip_config = priv->ip_config_x[IS_IPv4]; if (ip_config) { - const NMPlatformIPAddress *addr; + const NMPlatformIPAddress *addr = NULL; + + if (IS_IPv4) { + addr = nm_ip_config_get_first_address(ip_config); + } else { + /* For IPv6 prefer, in order: + * - !link-local, !deprecated + * - !link-local, deprecated + * - link-local + */ + addr = nm_ip_config_find_first_address(ip_config, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); + if (!addr) { + addr = nm_ip_config_find_first_address( + ip_config, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED); + } + if (!addr) { + addr = nm_ip_config_find_first_address(ip_config, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY); + } + } - addr = nm_ip_config_get_first_address(ip_config); if (addr) { new_address = g_inet_address_new_from_bytes(addr->address_ptr, IS_IPv4 ? G_SOCKET_FAMILY_IPV4