dns: fix handling default routing domains with systemd-resolved
We used to set "~." domains for all devices that should be used for resolving unknown domains. Systemd-resolved also supports setting "SetLinkDefaultRoute()". We should only set the wildcard domain if we want that this interface is used exclusively. Otherwise, we should only set DefaultRoute. See ([1], [2], [3], [4]). Otherwise the bad effect is if other components (wg-quick) want to set exclusive DNS lookups on their link. That is achieved by explicitly adding "~." and that is also what resolved's `/usr/sbin/resolvconf -x` does. If NetworkManager sets "~." for interfaces that are not important and should not be used exclusively, then this steals the DNS requests from those external components. In NetworkManager we know whether a link should get exclusive lookups based on the "ipv[46].dns-priority" setting. [1] https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html [2] https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html [3] https://github.com/systemd/systemd/issues/17529#issuecomment-730522444 [4] https://github.com/systemd/systemd/pull/17678
This commit is contained in:
@@ -820,11 +820,18 @@ add_ip_config(NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigD
|
|||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
addr = nm_ip_config_get_nameserver(ip_config, i);
|
addr = nm_ip_config_get_nameserver(ip_config, i);
|
||||||
ip_addr_to_string(addr_family, addr, iface, ip_addr_to_string_buf);
|
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) {
|
if (ip_data->domains.reverse) {
|
||||||
for (j = 0; ip_data->domains.reverse[j]; j++) {
|
for (j = 0; ip_data->domains.reverse[j]; j++) {
|
||||||
add_dnsmasq_nameserver(self,
|
add_dnsmasq_nameserver(self,
|
||||||
|
@@ -222,6 +222,26 @@ _ASSERT_ip_config_data(const NMDnsIPConfigData *ip_data)
|
|||||||
nm_assert(NM_IS_IP_CONFIG(ip_data->ip_config));
|
nm_assert(NM_IS_IP_CONFIG(ip_data->ip_config));
|
||||||
nm_assert(c_list_contains(&ip_data->data->data_lst_head, &ip_data->data_lst));
|
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));
|
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 *
|
static NMDnsIPConfigData *
|
||||||
@@ -1358,6 +1378,9 @@ rebuild_domain_lists(NMDnsManager *self)
|
|||||||
c_list_for_each_entry (ip_data, head, ip_config_lst) {
|
c_list_for_each_entry (ip_data, head, ip_config_lst) {
|
||||||
nm_assert(!ip_data->domains.search);
|
nm_assert(!ip_data->domains.search);
|
||||||
nm_assert(!ip_data->domains.reverse);
|
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
|
#endif
|
||||||
|
|
||||||
@@ -1398,8 +1421,11 @@ rebuild_domain_lists(NMDnsManager *self)
|
|||||||
guint n_domains;
|
guint n_domains;
|
||||||
guint num_dom1;
|
guint num_dom1;
|
||||||
guint num_dom2;
|
guint num_dom2;
|
||||||
guint cap_dom;
|
guint n_domains_allocated;
|
||||||
guint i;
|
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))
|
if (!nm_ip_config_get_num_nameservers(ip_config))
|
||||||
continue;
|
continue;
|
||||||
@@ -1413,12 +1439,6 @@ rebuild_domain_lists(NMDnsManager *self)
|
|||||||
nm_assert(prev_priority <= priority);
|
nm_assert(prev_priority <= priority);
|
||||||
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.
|
/* Add wildcard lookup domain to connections with the default route.
|
||||||
* If there is no default route, add the wildcard domain to all non-VPN
|
* If there is no default route, add the wildcard domain to all non-VPN
|
||||||
* connections */
|
* connections */
|
||||||
@@ -1429,12 +1449,17 @@ rebuild_domain_lists(NMDnsManager *self)
|
|||||||
* whether it is suitable for certain operations (like having an automatically
|
* whether it is suitable for certain operations (like having an automatically
|
||||||
* added "~" domain). */
|
* added "~" domain). */
|
||||||
if (g_hash_table_contains(wildcard_entries, ip_data))
|
if (g_hash_table_contains(wildcard_entries, ip_data))
|
||||||
domains[num_dom1++] = "~";
|
has_default_route_maybe = TRUE;
|
||||||
} else {
|
} else {
|
||||||
if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN)
|
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 */
|
/* searches are preferred over domains */
|
||||||
if (n_searches > 0) {
|
if (n_searches > 0) {
|
||||||
for (i = 0; i < n_searches; i++)
|
for (i = 0; i < n_searches; i++)
|
||||||
@@ -1444,32 +1469,55 @@ rebuild_domain_lists(NMDnsManager *self)
|
|||||||
domains[num_dom1++] = nm_ip_config_get_domain(ip_config, i);
|
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;
|
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 *domain_clean;
|
||||||
const char *parent;
|
const char *parent;
|
||||||
int old_priority;
|
int old_priority;
|
||||||
int parent_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 */
|
/* Remove domains with lower priority */
|
||||||
if (domain_ht_get_priority(ht, domain_clean, &old_priority)) {
|
if (domain_ht_get_priority(ht, domain_clean, &old_priority)) {
|
||||||
nm_assert(old_priority <= priority);
|
nm_assert(old_priority <= priority);
|
||||||
if (old_priority < priority) {
|
if (old_priority < priority) {
|
||||||
_LOGT(
|
_LOGT("plugin: drop domain %s%s%s (i=%d, p=%d) because it already exists "
|
||||||
"plugin: drop domain '%s' (i=%d, p=%d) because it already exists with p=%d",
|
"with p=%d",
|
||||||
domains[i],
|
NM_PRINT_FMT_QUOTED(!check_default_route,
|
||||||
ip_data->data->ifindex,
|
"'",
|
||||||
priority,
|
domain_full,
|
||||||
old_priority);
|
"'",
|
||||||
|
"<auto-default>"),
|
||||||
|
ip_data->data->ifindex,
|
||||||
|
priority,
|
||||||
|
old_priority);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (domain_is_shadowed(ht, domain_clean, priority, &parent, &parent_priority)) {
|
} 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)",
|
_LOGT("plugin: drop domain %s%s%s (i=%d, p=%d) shadowed by '%s' (p=%d)",
|
||||||
domains[i],
|
NM_PRINT_FMT_QUOTED(!check_default_route,
|
||||||
|
"'",
|
||||||
|
domain_full,
|
||||||
|
"'",
|
||||||
|
"<auto-default>"),
|
||||||
ip_data->data->ifindex,
|
ip_data->data->ifindex,
|
||||||
priority,
|
priority,
|
||||||
parent,
|
parent,
|
||||||
@@ -1477,22 +1525,38 @@ rebuild_domain_lists(NMDnsManager *self)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_LOGT("plugin: add domain '%s' (i=%d, p=%d)",
|
_LOGT(
|
||||||
domains[i],
|
"plugin: add domain %s%s%s (i=%d, p=%d)",
|
||||||
ip_data->data->ifindex,
|
NM_PRINT_FMT_QUOTED(!check_default_route, "'", domain_full, "'", "<auto-default>"),
|
||||||
priority);
|
ip_data->data->ifindex,
|
||||||
|
priority);
|
||||||
|
|
||||||
if (!ht)
|
if (!ht)
|
||||||
ht = g_hash_table_new(nm_str_hash, g_str_equal);
|
ht = g_hash_table_new(nm_str_hash, g_str_equal);
|
||||||
g_hash_table_insert(ht, (gpointer) domain_clean, GINT_TO_POINTER(priority));
|
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;
|
domains[num_dom2] = NULL;
|
||||||
|
|
||||||
nm_assert(!ip_data->domains.search);
|
nm_assert(!ip_data->domains.search);
|
||||||
nm_assert(!ip_data->domains.reverse);
|
nm_assert(!ip_data->domains.reverse);
|
||||||
ip_data->domains.search = domains;
|
ip_data->domains.search = domains;
|
||||||
ip_data->domains.reverse = get_ip_rdns_domains(ip_config);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1506,6 +1570,9 @@ clear_domain_lists(NMDnsManager *self)
|
|||||||
c_list_for_each_entry (ip_data, head, ip_config_lst) {
|
c_list_for_each_entry (ip_data, head, ip_config_lst) {
|
||||||
nm_clear_g_free(&ip_data->domains.search);
|
nm_clear_g_free(&ip_data->domains.search);
|
||||||
nm_clear_pointer(&ip_data->domains.reverse, g_strfreev);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -37,6 +37,28 @@ typedef struct {
|
|||||||
struct {
|
struct {
|
||||||
const char **search;
|
const char **search;
|
||||||
char ** reverse;
|
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;
|
} domains;
|
||||||
} NMDnsIPConfigData;
|
} NMDnsIPConfigData;
|
||||||
|
|
||||||
|
@@ -141,18 +141,18 @@ update_add_ip_config(NMDnsSystemdResolved *self,
|
|||||||
GVariantBuilder * domains,
|
GVariantBuilder * domains,
|
||||||
NMDnsIPConfigData * data)
|
NMDnsIPConfigData * data)
|
||||||
{
|
{
|
||||||
int addr_family;
|
int addr_family;
|
||||||
gsize addr_size;
|
gsize addr_size;
|
||||||
guint i, n;
|
guint i, n;
|
||||||
gboolean is_routing;
|
gboolean is_routing;
|
||||||
const char **iter;
|
const char *domain;
|
||||||
const char * domain;
|
gboolean has_config = FALSE;
|
||||||
gboolean has_config = FALSE;
|
|
||||||
|
|
||||||
addr_family = nm_ip_config_get_addr_family(data->ip_config);
|
addr_family = nm_ip_config_get_addr_family(data->ip_config);
|
||||||
addr_size = nm_utils_addr_family_to_size(addr_family);
|
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;
|
return FALSE;
|
||||||
|
|
||||||
n = nm_ip_config_get_num_nameservers(data->ip_config);
|
n = nm_ip_config_get_num_nameservers(data->ip_config);
|
||||||
@@ -169,11 +169,17 @@ update_add_ip_config(NMDnsSystemdResolved *self,
|
|||||||
has_config = TRUE;
|
has_config = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (iter = data->domains.search; *iter; iter++) {
|
if (!data->domains.has_default_route_explicit && data->domains.has_default_route_exclusive) {
|
||||||
domain = nm_utils_parse_dns_domain(*iter, &is_routing);
|
g_variant_builder_add(domains, "(sb)", ".", TRUE);
|
||||||
g_variant_builder_add(domains, "(sb)", domain[0] ? domain : ".", is_routing);
|
|
||||||
has_config = 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;
|
return has_config;
|
||||||
}
|
}
|
||||||
@@ -198,7 +204,8 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
|
|||||||
NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
|
NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
|
||||||
NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
|
NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
|
||||||
const char * mdns_arg = NULL, *llmnr_arg = NULL;
|
const char * mdns_arg = NULL, *llmnr_arg = NULL;
|
||||||
gboolean has_config = FALSE;
|
gboolean has_config = FALSE;
|
||||||
|
gboolean has_default_route = FALSE;
|
||||||
|
|
||||||
g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))"));
|
g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))"));
|
||||||
g_variant_builder_add(&dns, "i", ic->ifindex);
|
g_variant_builder_add(&dns, "i", ic->ifindex);
|
||||||
@@ -214,6 +221,9 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
|
|||||||
|
|
||||||
has_config |= update_add_ip_config(self, &dns, &domains, data);
|
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)) {
|
if (NM_IS_IP4_CONFIG(ip_config)) {
|
||||||
mdns = NM_MAX(mdns, nm_ip4_config_mdns_get(NM_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)));
|
llmnr = NM_MAX(llmnr, nm_ip4_config_llmnr_get(NM_IP4_CONFIG(ip_config)));
|
||||||
@@ -262,6 +272,9 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
|
|||||||
_request_item_append(&priv->request_queue_lst_head,
|
_request_item_append(&priv->request_queue_lst_head,
|
||||||
"SetLinkDomains",
|
"SetLinkDomains",
|
||||||
g_variant_builder_end(&domains));
|
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,
|
_request_item_append(&priv->request_queue_lst_head,
|
||||||
"SetLinkMulticastDNS",
|
"SetLinkMulticastDNS",
|
||||||
g_variant_new("(is)", ic->ifindex, mdns_arg ?: ""));
|
g_variant_new("(is)", ic->ifindex, mdns_arg ?: ""));
|
||||||
|
Reference in New Issue
Block a user