about summary refs log tree commit diff
path: root/src/dns/nm-dns-manager.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-06-04 00:08:31 +0200
committerMichael Biebl <biebl@debian.org>2018-06-04 00:08:31 +0200
commit0dd9df69fdbd475c48a0c8d5b0a1882550fe7321 (patch)
tree249cf25643b1fe408e10679bb61613bc6540e894 /src/dns/nm-dns-manager.c
parent2e94a3b93171ab3fb95bf689aab1664d23988809 (diff)
parent04bc9e1cd3544445d883ad29ea108c1645c8e7b7 (diff)
Update upstream source from tag 'upstream/1.11.4'
Update to upstream version '1.11.4'
with Debian dir d0638aa2e32d5bae4e8daa021b9a66b7c4d6647e
Diffstat (limited to 'src/dns/nm-dns-manager.c')
-rw-r--r--src/dns/nm-dns-manager.c206
1 files changed, 202 insertions, 4 deletions
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c
index 10a16e57..f5500ee7 100644
--- a/src/dns/nm-dns-manager.c
+++ b/src/dns/nm-dns-manager.c
@@ -232,7 +232,7 @@ _ASSERT_ip_config_data (const NMDnsIPConfigData *ip_data)
 {
 	nm_assert (ip_data);
 	_ASSERT_config_data (ip_data->data);
-	nm_assert (NM_IS_IP_CONFIG (ip_data->ip_config));
+	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));
 }
@@ -245,7 +245,7 @@ _ip_config_data_new (NMDnsConfigData *data,
 	NMDnsIPConfigData *ip_data;
 
 	_ASSERT_config_data (data);
-	nm_assert (NM_IS_IP_CONFIG (ip_config));
+	nm_assert (NM_IS_IP_CONFIG (ip_config, AF_UNSPEC));
 	nm_assert (ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED);
 
 	ip_data = g_slice_new0 (NMDnsIPConfigData);
@@ -273,6 +273,9 @@ _ip_config_data_free (NMDnsIPConfigData *ip_data)
 	c_list_unlink_stale (&ip_data->data_lst);
 	c_list_unlink_stale (&ip_data->ip_config_lst);
 
+	g_free (ip_data->domains.search);
+	g_strfreev (ip_data->domains.reverse);
+
 	g_signal_handlers_disconnect_by_func (ip_data->ip_config,
 	                                      _ip_config_dns_priority_changed,
 	                                      ip_data);
@@ -1136,6 +1139,197 @@ _collect_resolv_conf_data (NMDnsManager *self,
 	*out_nis_domain = rc.nis_domain;
 }
 
+static char **
+get_ip_rdns_domains (NMIPConfig *ip_config)
+{
+	int addr_family = nm_ip_config_get_addr_family (ip_config);
+	char **strv;
+	GPtrArray *domains = NULL;
+	NMDedupMultiIter ipconf_iter;
+
+	nm_assert_addr_family (addr_family);
+
+	domains = g_ptr_array_sized_new (5);
+
+	if (addr_family == AF_INET) {
+		NMIP4Config *ip4 = (gpointer) ip_config;
+		const NMPlatformIP4Address *address;
+		const NMPlatformIP4Route *route;
+
+		nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address)
+			nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
+
+		nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
+			if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+				nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
+		}
+	} else {
+		NMIP6Config *ip6 = (gpointer) ip_config;
+		const NMPlatformIP6Address *address;
+		const NMPlatformIP6Route *route;
+
+		nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address)
+			nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
+
+		nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
+			if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+				nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
+		}
+	}
+
+	/* Terminating NULL so we can use g_strfreev() to free it */
+	g_ptr_array_add (domains, NULL);
+
+	/* Free the array and return NULL if the only element was the ending NULL */
+	strv = (char **) g_ptr_array_free (domains, (domains->len == 1));
+
+	return _nm_utils_strv_cleanup (strv, FALSE, FALSE, TRUE);
+}
+
+/* Check if the domain is shadowed by a parent domain with more negative priority */
+static gboolean
+domain_is_shadowed (GHashTable *ht,
+                    const char *domain, int priority,
+                    const char **out_parent, int *out_parent_priority)
+{
+	char *parent;
+	int parent_priority;
+
+	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;
+	}
+
+	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;
+		}
+		parent = strchr (parent, '.');
+	}
+
+	return FALSE;
+}
+
+static void
+rebuild_domain_lists (NMDnsManager *self)
+{
+	NMDnsIPConfigData *ip_data;
+	gs_unref_hashtable GHashTable *ht = NULL;
+	gboolean default_route_found = FALSE;
+	CList *head;
+
+	ht = g_hash_table_new (nm_str_hash, g_str_equal);
+
+	head = _ip_config_lst_head (self);
+	c_list_for_each_entry (ip_data, head, ip_config_lst) {
+		NMIPConfig *ip_config = ip_data->ip_config;
+
+		if (!nm_ip_config_get_num_nameservers (ip_config))
+			continue;
+		if (nm_ip_config_best_default_route_get (ip_config)) {
+			default_route_found = TRUE;
+			break;
+		}
+	}
+
+	c_list_for_each_entry (ip_data, head, ip_config_lst) {
+		NMIPConfig *ip_config = ip_data->ip_config;
+		int priority, old_priority;
+		guint i, n, n_domains = 0;
+		const char **domains;
+
+		if (!nm_ip_config_get_num_nameservers (ip_config))
+			continue;
+
+		priority = nm_ip_config_get_dns_priority (ip_config);
+		nm_assert (priority != 0);
+		g_free (ip_data->domains.search);
+		domains = g_new0 (const char *,
+		                  2 + NM_MAX (nm_ip_config_get_num_searches (ip_config),
+		                              nm_ip_config_get_num_domains (ip_config)));
+		ip_data->domains.search = domains;
+
+		/* 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 */
+		if (default_route_found) {
+			if (nm_ip_config_best_default_route_get (ip_config))
+				domains[n_domains++] = "~";
+		} else {
+			if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN)
+				domains[n_domains++] = "~";
+		}
+
+		/* searches are preferred over domains */
+		n = nm_ip_config_get_num_searches (ip_config);
+		for (i = 0; i < n; i++)
+			domains[n_domains++] = nm_ip_config_get_search (ip_config, i);
+
+		if (n == 0) {
+			/* If not searches, use any domains */
+			n = nm_ip_config_get_num_domains (ip_config);
+			for (i = 0; i < n; i++)
+				domains[n_domains++] = nm_ip_config_get_domain (ip_config, i);
+		}
+
+		n = 0;
+		for (i = 0; i < n_domains; i++) {
+			const char *domain_clean;
+			const char *parent;
+			int parent_priority;
+
+			domain_clean = nm_utils_parse_dns_domain (domains[i], NULL);
+
+			/* Remove domains with lower priority */
+			old_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, domain_clean));
+			if (old_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);
+					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);
+				continue;
+			}
+
+			_LOGT ("plugin: add domain '%s' (i=%d, p=%d)", domains[i], ip_data->data->ifindex, priority);
+			g_hash_table_insert (ht, (gpointer) domain_clean, GINT_TO_POINTER (priority));
+			domains[n++] = domains[i];
+		}
+		domains[n] = NULL;
+
+		g_strfreev (ip_data->domains.reverse);
+		ip_data->domains.reverse = get_ip_rdns_domains (ip_config);
+	}
+}
+
+static void
+clear_domain_lists (NMDnsManager *self)
+{
+	NMDnsIPConfigData *ip_data;
+	CList *head;
+
+	head = _ip_config_lst_head (self);
+	c_list_for_each_entry (ip_data, head, ip_config_lst) {
+		g_clear_pointer (&ip_data->domains.search, g_free);
+		g_clear_pointer (&ip_data->domains.reverse, g_strfreev);
+	}
+}
+
 static gboolean
 update_dns (NMDnsManager *self,
             gboolean no_caching,
@@ -1198,6 +1392,7 @@ update_dns (NMDnsManager *self,
 		}
 
 		_LOGD ("update-dns: updating plugin %s", plugin_name);
+		rebuild_domain_lists (self);
 		if (!nm_dns_plugin_update (plugin,
 		                           global_config,
 		                           _ip_config_lst_head (self),
@@ -1209,6 +1404,10 @@ update_dns (NMDnsManager *self,
 			 */
 			caching = FALSE;
 		}
+		/* Clear the generated search list as it points to
+		 * strings owned by IP configurations and we can't
+		 * guarantee they stay alive. */
+		clear_domain_lists (self);
 
 	skip:
 		;
@@ -1363,7 +1562,7 @@ nm_dns_manager_set_ip_config (NMDnsManager *self,
 	NMDnsIPConfigData **p_best;
 
 	g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE);
-	g_return_val_if_fail (NM_IS_IP_CONFIG (ip_config), FALSE);
+	g_return_val_if_fail (NM_IS_IP_CONFIG (ip_config, AF_UNSPEC), FALSE);
 
 	ifindex = nm_ip_config_get_ifindex (ip_config);
 	g_return_val_if_fail (ifindex > 0, FALSE);
@@ -1951,7 +2150,6 @@ _get_config_variant (NMDnsManager *self)
 		                       "nameservers",
 		                       g_variant_builder_end (&strv_builder));
 
-
 		num = nm_ip_config_get_num_domains (ip_config);
 		num += nm_ip_config_get_num_searches (ip_config);
 		if (num > 0) {