diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index fdff3af16f..73ceeeb31e 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -788,14 +788,18 @@ add_ip_config (NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfig for (i = 0; i < num; i++) { addr = nm_ip_config_get_nameserver (ip_config, i); ip_addr_to_string (addr_family, addr, iface, ip_addr_to_string_buf); - for (j = 0; ip_data->domains.search[j]; j++) { - domain = nm_utils_parse_dns_domain (ip_data->domains.search[j], NULL); - add_dnsmasq_nameserver (self, - servers, - ip_addr_to_string_buf, - domain[0] ? domain : NULL); - } + if (!ip_data->domains.has_default_route_explicit && ip_data->domains.has_default_route) + add_dnsmasq_nameserver (self, servers, ip_addr_to_string_buf, NULL); + if (ip_data->domains.search) { + for (j = 0; ip_data->domains.search[j]; j++) { + domain = nm_utils_parse_dns_domain (ip_data->domains.search[j], NULL); + add_dnsmasq_nameserver (self, + servers, + ip_addr_to_string_buf, + domain[0] ? domain : NULL); + } + } if (ip_data->domains.reverse) { for (j = 0; ip_data->domains.reverse[j]; j++) { add_dnsmasq_nameserver (self, servers, diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index c467cdc2d7..d6e7b4d10a 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -218,6 +218,26 @@ _ASSERT_ip_config_data (const NMDnsIPConfigData *ip_data) nm_assert (NM_IS_IP_CONFIG (ip_data->ip_config, AF_UNSPEC)); nm_assert (c_list_contains (&ip_data->data->data_lst_head, &ip_data->data_lst)); nm_assert (ip_data->data->ifindex == nm_ip_config_get_ifindex (ip_data->ip_config)); +#if NM_MORE_ASSERTS > 5 + { + gboolean has_default = FALSE; + gsize i; + + for (i = 0; ip_data->domains.search && ip_data->domains.search; i++) { + const char *d = ip_data->domains.search[i]; + + d = nm_utils_parse_dns_domain (d, NULL); + nm_assert (d); + if (d[0] == '\0') + has_default = TRUE; + } + nm_assert (has_default == ip_data->domains.has_default_route_explicit); + if (ip_data->domains.has_default_route_explicit) + nm_assert (ip_data->domains.has_default_route_exclusive); + if (ip_data->domains.has_default_route_exclusive) + nm_assert (ip_data->domains.has_default_route); + } +#endif } static NMDnsIPConfigData * @@ -1330,6 +1350,9 @@ rebuild_domain_lists (NMDnsManager *self) c_list_for_each_entry (ip_data, head, ip_config_lst) { nm_assert (!ip_data->domains.search); nm_assert (!ip_data->domains.reverse); + nm_assert (!ip_data->domains.has_default_route_explicit); + nm_assert (!ip_data->domains.has_default_route_exclusive); + nm_assert (!ip_data->domains.has_default_route); } #endif @@ -1370,8 +1393,11 @@ rebuild_domain_lists (NMDnsManager *self) guint n_domains; guint num_dom1; guint num_dom2; - guint cap_dom; + guint n_domains_allocated; guint i; + gboolean has_default_route_maybe = FALSE; + gboolean has_default_route_explicit = FALSE; + gboolean has_default_route_auto = FALSE; if (!nm_ip_config_get_num_nameservers (ip_config)) continue; @@ -1385,12 +1411,6 @@ rebuild_domain_lists (NMDnsManager *self) nm_assert (prev_priority <= priority); prev_priority = priority; - cap_dom = 2u + NM_MAX (n_domains, n_searches); - - domains = g_new (const char *, cap_dom); - - num_dom1 = 0; - /* Add wildcard lookup domain to connections with the default route. * If there is no default route, add the wildcard domain to all non-VPN * connections */ @@ -1401,12 +1421,17 @@ rebuild_domain_lists (NMDnsManager *self) * whether it is suitable for certain operations (like having an automatically * added "~" domain). */ if (g_hash_table_contains (wildcard_entries, ip_data)) - domains[num_dom1++] = "~"; + has_default_route_maybe = TRUE; } else { if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN) - domains[num_dom1++] = "~"; + has_default_route_maybe = TRUE; } + n_domains_allocated = (n_searches > 0 ? n_searches : n_domains) + 1u; + domains = g_new (const char *, n_domains_allocated); + + num_dom1 = 0; + /* searches are preferred over domains */ if (n_searches > 0) { for (i = 0; i < n_searches; i++) @@ -1416,47 +1441,93 @@ rebuild_domain_lists (NMDnsManager *self) domains[num_dom1++] = nm_ip_config_get_domain (ip_config, i); } - nm_assert (num_dom1 < cap_dom); + nm_assert (num_dom1 < n_domains_allocated); num_dom2 = 0; - for (i = 0; i < num_dom1; i++) { + for (i = 0; TRUE; i++) { + const char *domain_full; const char *domain_clean; const char *parent; int old_priority; int parent_priority; + gboolean check_default_route; - domain_clean = nm_utils_parse_dns_domain (domains[i], NULL); + if (i < num_dom1) { + check_default_route = FALSE; + domain_full = domains[i]; + domain_clean = nm_utils_parse_dns_domain (domains[i], NULL); + } else if (i == num_dom1) { + if (!has_default_route_maybe) + continue; + if (has_default_route_explicit) + continue; + check_default_route = TRUE; + domain_full = "~"; + domain_clean = ""; + } else + break; /* Remove domains with lower priority */ if (domain_ht_get_priority (ht, domain_clean, &old_priority)) { nm_assert (old_priority <= priority); if (old_priority < priority) { - _LOGT ("plugin: drop domain '%s' (i=%d, p=%d) because it already exists with p=%d", - domains[i], ip_data->data->ifindex, - priority, old_priority); + _LOGT ("plugin: drop domain %s%s%s (i=%d, p=%d) because it already exists " + "with p=%d", + NM_PRINT_FMT_QUOTED (!check_default_route, + "'", + domain_full, + "'", + ""), + ip_data->data->ifindex, + priority, + old_priority); continue; } } else if (domain_is_shadowed (ht, domain_clean, priority, &parent, &parent_priority)) { - _LOGT ("plugin: drop domain '%s' (i=%d, p=%d) shadowed by '%s' (p=%d)", - domains[i], - ip_data->data->ifindex, priority, - parent, parent_priority); + _LOGT ("plugin: drop domain %s%s%s (i=%d, p=%d) shadowed by '%s' (p=%d)", + NM_PRINT_FMT_QUOTED (!check_default_route, + "'", + domain_full, + "'", + ""), + ip_data->data->ifindex, + priority, + parent, + parent_priority); continue; } - _LOGT ("plugin: add domain '%s' (i=%d, p=%d)", domains[i], ip_data->data->ifindex, priority); + _LOGT ("plugin: add domain %s%s%s (i=%d, p=%d)", + NM_PRINT_FMT_QUOTED (!check_default_route, "'", domain_full, "'", ""), + ip_data->data->ifindex, + priority); + if (!ht) ht = g_hash_table_new (nm_str_hash, g_str_equal); g_hash_table_insert (ht, (gpointer) domain_clean, GINT_TO_POINTER (priority)); - domains[num_dom2++] = domains[i]; + + if (check_default_route) + has_default_route_auto = TRUE; + else { + nm_assert (num_dom2 <= num_dom1); + nm_assert (num_dom2 < n_domains_allocated); + domains[num_dom2++] = domain_full; + if (domain_clean[0] == '\0') + has_default_route_explicit = TRUE; + } } - nm_assert (num_dom2 < cap_dom); + nm_assert (num_dom2 < n_domains_allocated); domains[num_dom2] = NULL; nm_assert (!ip_data->domains.search); nm_assert (!ip_data->domains.reverse); ip_data->domains.search = domains; ip_data->domains.reverse = get_ip_rdns_domains (ip_config); + ip_data->domains.has_default_route_explicit = has_default_route_explicit; + ip_data->domains.has_default_route_exclusive = has_default_route_explicit + || (priority < 0 && has_default_route_auto); + ip_data->domains.has_default_route = ip_data->domains.has_default_route_exclusive + || has_default_route_auto; } } @@ -1470,6 +1541,9 @@ clear_domain_lists (NMDnsManager *self) c_list_for_each_entry (ip_data, head, ip_config_lst) { nm_clear_g_free (&ip_data->domains.search); nm_clear_pointer (&ip_data->domains.reverse, g_strfreev); + ip_data->domains.has_default_route_explicit = FALSE; + ip_data->domains.has_default_route_exclusive = FALSE; + ip_data->domains.has_default_route = FALSE; } } diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index b60414566c..444d5d083c 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -37,6 +37,28 @@ typedef struct { struct { const char **search; char **reverse; + + /* Whether "search" explicitly contains a default route "~" + * or "". It is redundant information, but for faster lookup. */ + bool has_default_route_explicit : 1; + + /* Whether an explicit "~" search domain should be added. + * For systemd-resolved, this configured an explicit wildcard + * search domain, and should be used for profiles with negative + * DNS priority. + * + * If "has_default_route_explicit", this is always TRUE and implied. + * + * With systemd-resolved, if TRUE we will set a "." search domain. + */ + bool has_default_route_exclusive : 1; + + /* Whether the device should be used for any domains "~". + * + * If "has_default_route_exclusive", this is always TRUE and implied. + * + * With systemd-resolved, this is the value for SetLinkDefaultRoute(). */ + bool has_default_route : 1; } domains; } NMDnsIPConfigData; diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 159cd6f077..b2c9795293 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -146,14 +146,14 @@ update_add_ip_config (NMDnsSystemdResolved *self, gsize addr_size; guint i, n; gboolean is_routing; - const char **iter; const char *domain; gboolean has_config = FALSE; addr_family = nm_ip_config_get_addr_family (data->ip_config); addr_size = nm_utils_addr_family_to_size (addr_family); - if (!data->domains.search || !data->domains.search[0]) + if ((!data->domains.search || !data->domains.search[0]) + && !data->domains.has_default_route_exclusive) return FALSE; n = nm_ip_config_get_num_nameservers (data->ip_config); @@ -169,11 +169,17 @@ update_add_ip_config (NMDnsSystemdResolved *self, has_config = TRUE; } - for (iter = data->domains.search; *iter; iter++) { - domain = nm_utils_parse_dns_domain (*iter, &is_routing); - g_variant_builder_add (domains, "(sb)", domain[0] ? domain : ".", is_routing); + if (!data->domains.has_default_route_explicit && data->domains.has_default_route_exclusive) { + g_variant_builder_add (domains, "(sb)", ".", TRUE); has_config = TRUE; } + if (data->domains.search) { + for (i = 0; data->domains.search[i]; i++) { + domain = nm_utils_parse_dns_domain (data->domains.search[i], &is_routing); + g_variant_builder_add (domains, "(sb)", domain[0] ? domain : ".", is_routing); + has_config = TRUE; + } + } return has_config; } @@ -200,6 +206,7 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; const char *mdns_arg = NULL, *llmnr_arg = NULL; gboolean has_config = FALSE; + gboolean has_default_route = FALSE; g_variant_builder_init (&dns, G_VARIANT_TYPE ("(ia(iay))")); g_variant_builder_add (&dns, "i", ic->ifindex); @@ -215,6 +222,9 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) has_config |= update_add_ip_config (self, &dns, &domains, data); + if (data->domains.has_default_route) + has_default_route = TRUE; + if (NM_IS_IP4_CONFIG (ip_config)) { mdns = NM_MAX (mdns, nm_ip4_config_mdns_get (NM_IP4_CONFIG (ip_config))); llmnr = NM_MAX (llmnr, nm_ip4_config_llmnr_get (NM_IP4_CONFIG (ip_config))); @@ -265,6 +275,9 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) _request_item_append (&priv->request_queue_lst_head, "SetLinkDomains", g_variant_builder_end (&domains)); + _request_item_append (&priv->request_queue_lst_head, + "SetLinkDefaultRoute", + g_variant_new ("(ib)", ic->ifindex, has_default_route)); _request_item_append (&priv->request_queue_lst_head, "SetLinkMulticastDNS", g_variant_new ("(is)", ic->ifindex, mdns_arg ?: ""));