summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-11-20 18:29:05 +0100
committerThomas Haller <thaller@redhat.com>2020-11-20 18:29:47 +0100
commit4f19fd6ce2589d749e34521a48f724e74f7307ec (patch)
tree67cc1267c1ddcf1a0793cc5d2ea53dd2022547bc
parent34dd7d73bbd6ee680341942151a1b69c9d5d8c88 (diff)
parent95017dccdd2aa390053d3d3a16273daf937535b0 (diff)
downloadNetworkManager-4f19fd6ce2589d749e34521a48f724e74f7307ec.tar.gz
dns: merge branch 'th/dns-resolved-fix-exclusive'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/687
-rw-r--r--src/dns/nm-dns-dnsmasq.c15
-rw-r--r--src/dns/nm-dns-manager.c236
-rw-r--r--src/dns/nm-dns-manager.h24
-rw-r--r--src/dns/nm-dns-systemd-resolved.c39
4 files changed, 238 insertions, 76 deletions
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c
index 451e48465a..97f1dfabf8 100644
--- a/src/dns/nm-dns-dnsmasq.c
+++ b/src/dns/nm-dns-dnsmasq.c
@@ -820,11 +820,18 @@ add_ip_config(NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsIPConfigD
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,
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c
index 0ea5f6f6a9..74b8a72648 100644
--- a/src/dns/nm-dns-manager.c
+++ b/src/dns/nm-dns-manager.c
@@ -222,6 +222,26 @@ _ASSERT_ip_config_data(const NMDnsIPConfigData *ip_data)
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(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 *
@@ -233,10 +253,12 @@ _ip_config_data_new(NMDnsConfigData *data, NMIPConfig *ip_config, NMDnsIPConfigT
nm_assert(NM_IS_IP_CONFIG(ip_config));
nm_assert(ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED);
- ip_data = g_slice_new0(NMDnsIPConfigData);
- ip_data->data = data;
- ip_data->ip_config = g_object_ref(ip_config);
- ip_data->ip_config_type = ip_config_type;
+ ip_data = g_slice_new(NMDnsIPConfigData);
+ *ip_data = (NMDnsIPConfigData){
+ .data = data,
+ .ip_config = g_object_ref(ip_config),
+ .ip_config_type = ip_config_type,
+ };
c_list_link_tail(&data->data_lst_head, &ip_data->data_lst);
c_list_link_tail(&NM_DNS_MANAGER_GET_PRIVATE(data->self)->ip_config_lst_head,
&ip_data->ip_config_lst);
@@ -267,7 +289,7 @@ _ip_config_data_free(NMDnsIPConfigData *ip_data)
ip_data);
g_object_unref(ip_data->ip_config);
- g_slice_free(NMDnsIPConfigData, ip_data);
+ nm_g_slice_free(ip_data);
}
static NMDnsIPConfigData *
@@ -292,7 +314,7 @@ _config_data_free(NMDnsConfigData *data)
_ASSERT_config_data(data);
nm_assert(c_list_is_empty(&data->data_lst_head));
- g_slice_free(NMDnsConfigData, data);
+ nm_g_slice_free(data);
}
static int
@@ -1284,6 +1306,19 @@ get_ip_rdns_domains(NMIPConfig *ip_config)
return _nm_utils_strv_cleanup(strv, FALSE, FALSE, TRUE);
}
+static gboolean
+domain_ht_get_priority(GHashTable *ht, const char *domain, int *out_priority)
+{
+ gpointer ptr;
+
+ if (!ht || !g_hash_table_lookup_extended(ht, domain, NULL, &ptr)) {
+ *out_priority = 0;
+ return FALSE;
+ }
+ *out_priority = GPOINTER_TO_INT(ptr);
+ return TRUE;
+}
+
/* Check if the domain is shadowed by a parent domain with more negative priority */
static gboolean
domain_is_shadowed(GHashTable * ht,
@@ -1300,21 +1335,25 @@ domain_is_shadowed(GHashTable * ht,
nm_assert(!g_hash_table_contains(ht, domain));
- parent_priority = GPOINTER_TO_INT(g_hash_table_lookup(ht, ""));
- if (parent_priority < 0 && parent_priority < priority) {
- *out_parent = "";
- *out_parent_priority = parent_priority;
- return TRUE;
+ if (domain_ht_get_priority(ht, "", &parent_priority)) {
+ nm_assert(parent_priority <= priority);
+ if (parent_priority < 0 && parent_priority < priority) {
+ *out_parent = "";
+ *out_parent_priority = parent_priority;
+ return TRUE;
+ }
}
parent = strchr(domain, '.');
while (parent && parent[1]) {
parent++;
- parent_priority = GPOINTER_TO_INT(g_hash_table_lookup(ht, parent));
- if (parent_priority < 0 && parent_priority < priority) {
- *out_parent = parent;
- *out_parent_priority = parent_priority;
- return TRUE;
+ if (domain_ht_get_priority(ht, parent, &parent_priority)) {
+ nm_assert(parent_priority <= priority);
+ if (parent_priority < 0 && parent_priority < priority) {
+ *out_parent = parent;
+ *out_parent_priority = parent_priority;
+ return TRUE;
+ }
}
parent = strchr(parent, '.');
}
@@ -1329,8 +1368,22 @@ rebuild_domain_lists(NMDnsManager *self)
gs_unref_hashtable GHashTable *ht = NULL;
gs_unref_hashtable GHashTable *wildcard_entries = NULL;
CList * head;
+ int prev_priority = G_MININT;
head = _ip_config_lst_head(self);
+
+#if NM_MORE_ASSERTS
+ /* we call clear_domain_lists() at the end of update. We
+ * don't expect any domain settings here. */
+ 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
+
c_list_for_each_entry (ip_data, head, ip_config_lst) {
NMIPConfig *ip_config = ip_data->ip_config;
gboolean add_wildcard = FALSE;
@@ -1368,8 +1421,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;
@@ -1378,15 +1434,10 @@ rebuild_domain_lists(NMDnsManager *self)
n_domains = nm_ip_config_get_num_domains(ip_config);
priority = nm_ip_config_get_dns_priority(ip_config);
- nm_assert(priority != 0);
-
- cap_dom = 2u + NM_MAX(n_domains, n_searches);
-
- g_free(ip_data->domains.search);
- domains = g_new(const char *, cap_dom);
- ip_data->domains.search = domains;
- num_dom1 = 0;
+ nm_assert(priority != 0);
+ nm_assert(prev_priority <= priority);
+ prev_priority = priority;
/* Add wildcard lookup domain to connections with the default route.
* If there is no default route, add the wildcard domain to all non-VPN
@@ -1398,12 +1449,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++)
@@ -1413,32 +1469,55 @@ 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;
-
- domain_clean = nm_utils_parse_dns_domain(domains[i], NULL);
+ gboolean check_default_route;
+
+ 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 */
- old_priority = GPOINTER_TO_INT(nm_g_hash_table_lookup(ht, domain_clean));
- if (old_priority != 0) {
+ 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,
+ "'",
+ "<auto-default>"),
+ 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],
+ _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,
+ "'",
+ "<auto-default>"),
ip_data->data->ifindex,
priority,
parent,
@@ -1446,20 +1525,53 @@ rebuild_domain_lists(NMDnsManager *self)
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, "'", "<auto-default>"),
+ 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;
- g_strfreev(ip_data->domains.reverse);
- ip_data->domains.reverse = get_ip_rdns_domains(ip_config);
+ 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;
+
+ {
+ gs_free char *str1 = NULL;
+ gs_free char *str2 = NULL;
+
+ _LOGT("plugin: settings: ifindex=%d, priority=%d, default-route=%d%s, search=%s, reverse=%s",
+ ip_data->data->ifindex,
+ priority,
+ ip_data->domains.has_default_route,
+ ip_data->domains.has_default_route_explicit
+ ? " (explicit)"
+ : (ip_data->domains.has_default_route_exclusive ? " (exclusive)" : ""),
+ (str1 = g_strjoinv(",", (char **) ip_data->domains.search)),
+ (str2 = g_strjoinv(",", ip_data->domains.reverse)));
+ }
}
}
@@ -1473,6 +1585,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;
}
}
@@ -1714,7 +1829,7 @@ nm_dns_manager_set_ip_config(NMDnsManager * self,
priv = NM_DNS_MANAGER_GET_PRIVATE(self);
- data = g_hash_table_lookup(priv->configs, GINT_TO_POINTER(ifindex));
+ data = g_hash_table_lookup(priv->configs, &ifindex);
if (!data)
ip_data = NULL;
else
@@ -1730,7 +1845,7 @@ nm_dns_manager_set_ip_config(NMDnsManager * self,
/* deleting a config doesn't invalidate the configs' sort order. */
_ip_config_data_free(ip_data);
if (c_list_is_empty(&data->data_lst_head))
- g_hash_table_remove(priv->configs, GINT_TO_POINTER(ifindex));
+ g_hash_table_remove(priv->configs, &ifindex);
goto changed;
}
@@ -1740,12 +1855,14 @@ nm_dns_manager_set_ip_config(NMDnsManager * self,
}
if (!data) {
- data = g_slice_new0(NMDnsConfigData);
- data->ifindex = ifindex;
- data->self = self;
- c_list_init(&data->data_lst_head);
+ data = g_slice_new(NMDnsConfigData);
+ *data = (NMDnsConfigData){
+ .ifindex = ifindex,
+ .self = self,
+ .data_lst_head = C_LIST_INIT(data->data_lst_head),
+ };
_ASSERT_config_data(data);
- g_hash_table_insert(priv->configs, GINT_TO_POINTER(ifindex), data);
+ g_hash_table_add(priv->configs, data);
}
if (!ip_data)
@@ -2398,8 +2515,11 @@ nm_dns_manager_init(NMDnsManager *self)
priv->config = g_object_ref(nm_config_get());
- priv->configs =
- g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) _config_data_free);
+ G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDnsConfigData, ifindex) == 0);
+ priv->configs = g_hash_table_new_full(nm_pint_hash,
+ nm_pint_equals,
+ (GDestroyNotify) _config_data_free,
+ NULL);
/* Set the initial hash */
compute_hash(self, NULL, NM_DNS_MANAGER_GET_PRIVATE(self)->hash);
diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h
index f91d1556bc..37d62a124e 100644
--- a/src/dns/nm-dns-manager.h
+++ b/src/dns/nm-dns-manager.h
@@ -37,13 +37,35 @@ 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;
typedef struct _NMDnsConfigData {
+ int ifindex;
struct _NMDnsManager *self;
CList data_lst_head;
- int ifindex;
} NMDnsConfigData;
#define NM_TYPE_DNS_MANAGER (nm_dns_manager_get_type())
diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c
index f1d08f67be..4db7da4195 100644
--- a/src/dns/nm-dns-systemd-resolved.c
+++ b/src/dns/nm-dns-systemd-resolved.c
@@ -141,18 +141,18 @@ update_add_ip_config(NMDnsSystemdResolved *self,
GVariantBuilder * domains,
NMDnsIPConfigData * data)
{
- int addr_family;
- gsize addr_size;
- guint i, n;
- gboolean is_routing;
- const char **iter;
- const char * domain;
- gboolean has_config = FALSE;
+ int addr_family;
+ gsize addr_size;
+ guint i, n;
+ gboolean is_routing;
+ 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;
}
@@ -198,7 +204,8 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
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_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);
+ 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)));
@@ -258,16 +268,19 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
if (!nm_str_is_empty(mdns_arg) || !nm_str_is_empty(llmnr_arg))
has_config = TRUE;
- _request_item_append(&priv->request_queue_lst_head, "SetLinkDNS", g_variant_builder_end(&dns));
_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 ?: ""));
_request_item_append(&priv->request_queue_lst_head,
"SetLinkLLMNR",
g_variant_new("(is)", ic->ifindex, llmnr_arg ?: ""));
+ _request_item_append(&priv->request_queue_lst_head, "SetLinkDNS", g_variant_builder_end(&dns));
return has_config;
}