From 1803370cb24c0f78fdcea5a7cb4f00c1404422fc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 17 Aug 2021 11:16:51 +0200 Subject: [PATCH 1/5] glib-aux: add nm_dedup_multi_iter_init_reverse() to iterate in reverse order (cherry picked from commit 57a519cc035a55ed51c5e5fd1390eb387d342e8f) --- src/libnm-glib-aux/nm-dedup-multi.h | 40 +++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/libnm-glib-aux/nm-dedup-multi.h b/src/libnm-glib-aux/nm-dedup-multi.h index 9a995ec5d4..75cc193363 100644 --- a/src/libnm-glib-aux/nm-dedup-multi.h +++ b/src/libnm-glib-aux/nm-dedup-multi.h @@ -309,8 +309,11 @@ guint nm_dedup_multi_index_dirty_remove_idx(NMDedupMultiIndex * self, /*****************************************************************************/ typedef struct _NMDedupMultiIter { - const CList * _head; - const CList * _next; + const CList *_head; + union { + const CList *_next; + const CList *_prev; + }; const NMDedupMultiEntry *current; } NMDedupMultiIter; @@ -329,6 +332,21 @@ nm_dedup_multi_iter_init(NMDedupMultiIter *iter, const NMDedupMultiHeadEntry *he iter->current = NULL; } +static inline void +nm_dedup_multi_iter_init_reverse(NMDedupMultiIter *iter, const NMDedupMultiHeadEntry *head) +{ + g_return_if_fail(iter); + + if (head && !c_list_is_empty(&head->lst_entries_head)) { + iter->_head = &head->lst_entries_head; + iter->_prev = head->lst_entries_head.prev; + } else { + iter->_head = NULL; + iter->_prev = NULL; + } + iter->current = NULL; +} + static inline gboolean nm_dedup_multi_iter_next(NMDedupMultiIter *iter) { @@ -347,6 +365,24 @@ nm_dedup_multi_iter_next(NMDedupMultiIter *iter) return TRUE; } +static inline gboolean +nm_dedup_multi_iter_prev(NMDedupMultiIter *iter) +{ + g_return_val_if_fail(iter, FALSE); + + if (!iter->_prev) + return FALSE; + + /* we always look ahead for the prev. This way, the user + * may delete the current entry (but no other entries). */ + iter->current = c_list_entry(iter->_prev, NMDedupMultiEntry, lst_entries); + if (iter->_prev->prev == iter->_head) + iter->_prev = NULL; + else + iter->_prev = iter->_prev->prev; + return TRUE; +} + #define nm_dedup_multi_iter_for_each(iter, head_entry) \ for (nm_dedup_multi_iter_init((iter), (head_entry)); nm_dedup_multi_iter_next((iter));) From e60c52829c6256237645ca6aa7cbb3576f9e4453 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 17 Aug 2021 19:18:42 +0200 Subject: [PATCH 2/5] glib-aux: clear iterator in nm_dedup_multi_iter_{next,prev}() at the end It seems slightly nicer not to leave a dangling pointer at the end of the iteration. Then you could do something like nm_dedup_multi_iter_init(&iter, head_entry); while (nm_dedup_multi_iter_next(&iter)) { if (some_condition()) break; } if (!iter.current) printf("iterated to the end\n"); As nm_dedup_multi_iter_next() and nm_dedup_multi_iter_init() are inline functions, the compiler should even be able to see that the initial setting becomes unnecessary (the field will be initialized by the first nm_dedup_multi_iter_next()). Likewise, the final clearing of the field might also be optimized away at the end of the iteration (if, as in the common case, the iterator is not accessed afterwards). (cherry picked from commit 53070705b0f033aed4c7891b7e0eb19534c1c8d7) --- src/libnm-glib-aux/nm-dedup-multi.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libnm-glib-aux/nm-dedup-multi.h b/src/libnm-glib-aux/nm-dedup-multi.h index 75cc193363..fb1cb86340 100644 --- a/src/libnm-glib-aux/nm-dedup-multi.h +++ b/src/libnm-glib-aux/nm-dedup-multi.h @@ -352,8 +352,10 @@ nm_dedup_multi_iter_next(NMDedupMultiIter *iter) { g_return_val_if_fail(iter, FALSE); - if (!iter->_next) + if (!iter->_next) { + iter->current = NULL; return FALSE; + } /* we always look ahead for the next. This way, the user * may delete the current entry (but no other entries). */ @@ -370,8 +372,10 @@ nm_dedup_multi_iter_prev(NMDedupMultiIter *iter) { g_return_val_if_fail(iter, FALSE); - if (!iter->_prev) + if (!iter->_prev) { + iter->current = NULL; return FALSE; + } /* we always look ahead for the prev. This way, the user * may delete the current entry (but no other entries). */ From feaa4943a0e715013603335bcd0075371fd130a0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 17 Aug 2021 11:19:35 +0200 Subject: [PATCH 3/5] platform: add nmp_cache_iter_for_each_reverse() helper (cherry picked from commit 9c99c948fd8c3c72b09d8de56f5424ef32061794) --- .clang-format | 1 + src/libnm-platform/nmp-object.h | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/.clang-format b/.clang-format index 8538f3dfe8..8993cb0652 100644 --- a/.clang-format +++ b/.clang-format @@ -120,4 +120,5 @@ ForEachMacros: ['c_list_for_each', 'nm_platform_iter_obj_for_each', 'nmp_cache_iter_for_each', 'nmp_cache_iter_for_each_link', + 'nmp_cache_iter_for_each_reverse', ] diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index e3e101eef3..021829db4b 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -777,6 +777,18 @@ nmp_cache_iter_next(NMDedupMultiIter *iter, const NMPObject **out_obj) return has_next; } +static inline gboolean +nmp_cache_iter_prev(NMDedupMultiIter *iter, const NMPObject **out_obj) +{ + gboolean has_prev; + + has_prev = nm_dedup_multi_iter_prev(iter); + nm_assert(!has_prev || NMP_OBJECT_IS_VALID(iter->current->obj)); + if (out_obj) + *out_obj = has_prev ? iter->current->obj : NULL; + return has_prev; +} + static inline gboolean nmp_cache_iter_next_link(NMDedupMultiIter *iter, const NMPlatformLink **out_obj) { @@ -792,6 +804,9 @@ nmp_cache_iter_next_link(NMDedupMultiIter *iter, const NMPlatformLink **out_obj) #define nmp_cache_iter_for_each(iter, head, obj) \ for (nm_dedup_multi_iter_init((iter), (head)); nmp_cache_iter_next((iter), (obj));) +#define nmp_cache_iter_for_each_reverse(iter, head, obj) \ + for (nm_dedup_multi_iter_init_reverse((iter), (head)); nmp_cache_iter_prev((iter), (obj));) + #define nmp_cache_iter_for_each_link(iter, head, obj) \ for (nm_dedup_multi_iter_init((iter), (head)); nmp_cache_iter_next_link((iter), (obj));) From 823b94290bbd64325fae7df8aed961978e5af760 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 17 Aug 2021 11:21:17 +0200 Subject: [PATCH 4/5] platform: capture NMIP[46]Config from platform with correct (reversed) order of IP addresses Fix the order of IP addresses when assuming devices (service restart). The order of IP addresses matters to kernel for selection of source IP address. If all other properties are equal ([1]), for IPv6, the address added *last* will be preferred. That is the address you see *first*` in `ip -6 addr show`. NMPlatform also preserves that order, so the address *first* is the most important one. On the other hand, in a connection profile, `ipv6.addresses` lists addresses in increasing priority (the last address is the primary one). That is for compatibility with initscripts, which iterates over the list of addresses and calls `ip addr add` (meaning, the last address will be added last and is thus preferred by kernel). As the priority order in the profile is reversed, also the priority order in NMIP[46]Config is reversed. Fix creating an NMIP[46]Config instance from platform addresses to honor the priority. This has real consequences. When restarting NetworkManager, the interface stays up with the addresses configured in the right order. After restart, the device gets assumed, which means that the NMIP[46]Config instance from the connection is not yet set, only the config from the platform gets synchronized. Previously the order was wrong, so during restart the order of IP addresses was reverted. [1] https://access.redhat.com/solutions/189153 https://bugzilla.redhat.com/show_bug.cgi?id=1988751 (cherry picked from commit c631aa48f034ade2b5cb97ccc4462d56d80174e7) --- src/core/nm-ip4-config.c | 21 +-------------------- src/core/nm-ip6-config.c | 7 +------ 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/core/nm-ip4-config.c b/src/core/nm-ip4-config.c index e7e90c4330..90531d0291 100644 --- a/src/core/nm-ip4-config.c +++ b/src/core/nm-ip4-config.c @@ -512,22 +512,6 @@ _notify_routes(NMIP4Config *self) /*****************************************************************************/ -static int -sort_captured_addresses(const CList *lst_a, const CList *lst_b, gconstpointer user_data) -{ - const NMPlatformIP4Address *addr_a = - NMP_OBJECT_CAST_IP4_ADDRESS(c_list_entry(lst_a, NMDedupMultiEntry, lst_entries)->obj); - const NMPlatformIP4Address *addr_b = - NMP_OBJECT_CAST_IP4_ADDRESS(c_list_entry(lst_b, NMDedupMultiEntry, lst_entries)->obj); - - nm_assert(addr_a); - nm_assert(addr_b); - - /* Primary addresses first */ - return NM_FLAGS_HAS(addr_a->n_ifa_flags, IFA_F_SECONDARY) - - NM_FLAGS_HAS(addr_b->n_ifa_flags, IFA_F_SECONDARY); -} - NMIP4Config * nm_ip4_config_clone(const NMIP4Config *self) { @@ -559,7 +543,7 @@ nm_ip4_config_capture(NMDedupMultiIndex *multi_idx, NMPlatform *platform, int if head_entry = nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); if (head_entry) { - nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + nmp_cache_iter_for_each_reverse (&iter, head_entry, &plobj) { if (!_nm_ip_config_add_obj(priv->multi_idx, &priv->idx_ip4_addresses_, ifindex, @@ -571,9 +555,6 @@ nm_ip4_config_capture(NMDedupMultiIndex *multi_idx, NMPlatform *platform, int if NULL)) nm_assert_not_reached(); } - head_entry = nm_ip4_config_lookup_addresses(self); - nm_assert(head_entry); - nm_dedup_multi_head_entry_sort(head_entry, sort_captured_addresses, NULL); _notify_addresses(self); } diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c index d2ecf1759b..65e8473749 100644 --- a/src/core/nm-ip6-config.c +++ b/src/core/nm-ip6-config.c @@ -316,7 +316,7 @@ nm_ip6_config_capture(NMDedupMultiIndex * multi_idx, head_entry = nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex); if (head_entry) { - nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + nmp_cache_iter_for_each_reverse (&iter, head_entry, &plobj) { if (!_nm_ip_config_add_obj(priv->multi_idx, &priv->idx_ip6_addresses_, ifindex, @@ -328,11 +328,6 @@ nm_ip6_config_capture(NMDedupMultiIndex * multi_idx, NULL)) nm_assert_not_reached(); } - head_entry = nm_ip6_config_lookup_addresses(self); - nm_assert(head_entry); - nm_dedup_multi_head_entry_sort(head_entry, - sort_captured_addresses, - GINT_TO_POINTER(use_temporary)); _notify_addresses(self); } From 8e05b05135a8d63b83b8f114b7e0226c46dd600b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 17 Aug 2021 12:12:40 +0200 Subject: [PATCH 5/5] nmcli/docs: better describe ipv[46].addresses in `man nm-settings-nmcli` (cherry picked from commit 7aa4ad0fa22c105d4585b953f35817fe4326a221) --- src/libnm-core-impl/nm-setting-ip4-config.c | 2 ++ src/libnm-core-impl/nm-setting-ip6-config.c | 9 +++++++++ src/libnmc-setting/settings-docs.h.in | 4 ++-- src/nmcli/generate-docs-nm-settings-nmcli.xml.in | 4 ++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c index 15bae0cd40..b3a18bcae7 100644 --- a/src/libnm-core-impl/nm-setting-ip4-config.c +++ b/src/libnm-core-impl/nm-setting-ip4-config.c @@ -967,6 +967,8 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * format: a comma separated list of addresses * description: A list of IPv4 addresses and their prefix length. Multiple addresses * can be separated by comma. For example "192.168.1.5/24, 10.1.0.5/24". + * The addresses are listed in increasing priority, meaning the last address will + * be the primary address. * ---end--- */ _nm_properties_override_gobj( diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c index f6d59a46d1..ee72de574d 100644 --- a/src/libnm-core-impl/nm-setting-ip6-config.c +++ b/src/libnm-core-impl/nm-setting-ip6-config.c @@ -1030,6 +1030,15 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * that subnet. * ---end--- */ + /* ---nmcli--- + * property: addresses + * format: a comma separated list of addresses + * description: A list of IPv6 addresses and their prefix length. Multiple addresses + * can be separated by comma. For example "2001:db8:85a3::8a2e:370:7334/64, 2001:db8:85a3::5/64". + * The addresses are listed in increasing priority, meaning the last address will + * be the primary address. + * ---end--- + */ _nm_properties_override_gobj( properties_override, g_object_class_find_property(G_OBJECT_CLASS(setting_class), NM_SETTING_IP_CONFIG_ADDRESSES), diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index 256ce62653..12625d4459 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -226,7 +226,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_REMOTE N_("The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address.") #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.") #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.") -#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example \"192.168.1.5/24, 10.1.0.5/24\".") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example \"192.168.1.5/24, 10.1.0.5/24\". The addresses are listed in increasing priority, meaning the last address will be the primary address.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value \"ipv6-duid\" uses the DUID from \"ipv6.dhcp-duid\" property as an RFC4361-compliant client identifier. As IAID it uses \"ipv4.dhcp-iaid\" and falls back to \"ipv6.dhcp-iaid\" if unset. The special value \"duid\" generates a RFC4361-compliant client identifier based on \"ipv4.dhcp-iaid\" and uses a DUID generated by hashing /etc/machine-id. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the \"${DEVICE}\" or \"${MAC}\" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_FQDN N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-hostname\" are mutually exclusive and cannot be set at the same time.") @@ -252,7 +252,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTES N_("A list of IPv4 destination addresses, prefix length, optional IPv4 next hop addresses, optional route metric, optional attribute. The valid syntax is: \"ip[/prefix] [next-hop] [metric] [attribute=val]...[,ip[/prefix]...]\". For example \"192.0.2.0/24 10.1.1.1 77, 198.51.100.0/24\".") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("A list of IPv6 addresses and their prefix length. Multiple addresses can be separated by comma. For example \"2001:db8:85a3::8a2e:370:7334/64, 2001:db8:85a3::5/64\". The addresses are listed in increasing priority, meaning the last address will be the primary address.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the \"${DEVICE}\" or \"${MAC}\" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.") diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in index 7e8ffad63f..88803094d6 100644 --- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in @@ -650,7 +650,7 @@ description="DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured." /> + description="A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example "192.168.1.5/24, 10.1.0.5/24". The addresses are listed in increasing priority, meaning the last address will be the primary address." /> @@ -705,7 +705,7 @@ description="DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured." /> + description="A list of IPv6 addresses and their prefix length. Multiple addresses can be separated by comma. For example "2001:db8:85a3::8a2e:370:7334/64, 2001:db8:85a3::5/64". The addresses are listed in increasing priority, meaning the last address will be the primary address." />