summary refs log tree commit diff
path: root/src/dns
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/nm-dns-dnsmasq.c32
-rw-r--r--src/dns/nm-dns-manager.c88
-rw-r--r--src/dns/nm-dns-systemd-resolved.c123
3 files changed, 136 insertions, 107 deletions
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c
index a6204ae4..3ec1fd2d 100644
--- a/src/dns/nm-dns-dnsmasq.c
+++ b/src/dns/nm-dns-dnsmasq.c
@@ -80,22 +80,20 @@ get_ip4_rdns_domains (NMIP4Config *ip4)
 {
 	char **strv;
 	GPtrArray *domains = NULL;
-	int i;
+	NMDedupMultiIter ipconf_iter;
+	const NMPlatformIP4Address *address;
+	const NMPlatformIP4Route *route;
 
 	g_return_val_if_fail (ip4 != NULL, NULL);
 
 	domains = g_ptr_array_sized_new (5);
 
-	for (i = 0; i < nm_ip4_config_get_num_addresses (ip4); i++) {
-		const NMPlatformIP4Address *address = nm_ip4_config_get_address (ip4, i);
-
+	nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address)
 		nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
-	}
-
-	for (i = 0; i < nm_ip4_config_get_num_routes (ip4); i++) {
-		const NMPlatformIP4Route *route = nm_ip4_config_get_route (ip4, i);
 
-		nm_utils_get_reverse_dns_domains_ip4 (route->network, route->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);
 	}
 
 	/* Terminating NULL so we can use g_strfreev() to free it */
@@ -112,22 +110,20 @@ get_ip6_rdns_domains (NMIP6Config *ip6)
 {
 	char **strv;
 	GPtrArray *domains = NULL;
-	int i;
+	NMDedupMultiIter ipconf_iter;
+	const NMPlatformIP6Address *address;
+	const NMPlatformIP6Route *route;
 
 	g_return_val_if_fail (ip6 != NULL, NULL);
 
 	domains = g_ptr_array_sized_new (5);
 
-	for (i = 0; i < nm_ip6_config_get_num_addresses (ip6); i++) {
-		const NMPlatformIP6Address *address = nm_ip6_config_get_address (ip6, i);
-
+	nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address)
 		nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
-	}
-
-	for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) {
-		const NMPlatformIP6Route *route = nm_ip6_config_get_route (ip6, i);
 
-		nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->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 */
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c
index 952468e3..d5392b7d 100644
--- a/src/dns/nm-dns-manager.c
+++ b/src/dns/nm-dns-manager.c
@@ -497,7 +497,7 @@ dispatch_netconfig (NMDnsManager *self,
 		g_free (str);
 	}
 
-	close (fd);
+	nm_close (fd);
 
 	/* Wait until the process exits */
 	if (!nm_utils_kill_child_sync (pid, 0, LOGD_DNS, "netconfig", &status, 1000, 0)) {
@@ -1167,9 +1167,16 @@ update_dns (NMDnsManager *self,
 	 * but only uses the local caching nameserver.
 	 */
 	if (caching) {
+		const char *lladdr = "127.0.0.1";
+
+		if (NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin)) {
+			/* systemd-resolved uses a different link-local address */
+			lladdr = "127.0.0.53";
+		}
+
 		g_strfreev (nameservers);
-		nameservers = g_new0 (char*, 2);
-		nameservers[0] = g_strdup ("127.0.0.1");
+		nameservers = g_new0 (char *, 2);
+		nameservers[0] = g_strdup (lladdr);
 	}
 
 	if (update) {
@@ -1427,6 +1434,7 @@ nm_dns_manager_set_initial_hostname (NMDnsManager *self,
 {
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
+	g_free (priv->hostname);
 	priv->hostname = g_strdup (hostname);
 }
 
@@ -1625,7 +1633,7 @@ _check_resconf_immutable (NMDnsManagerResolvConfManager rc_manager)
 		if (fd != -1) {
 			if (ioctl (fd, FS_IOC_GETFLAGS, &flags) != -1)
 				immutable = NM_FLAGS_HAS (flags, FS_IMMUTABLE_FL);
-			close (fd);
+			nm_close (fd);
 		}
 		return immutable ? NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE : rc_manager;
 	}
@@ -1634,32 +1642,68 @@ _check_resconf_immutable (NMDnsManagerResolvConfManager rc_manager)
 static gboolean
 _resolvconf_resolved_managed (void)
 {
-	static const char *const resolved_paths[] = {
+	static const char *const RESOLVED_PATHS[] = {
 		"/run/systemd/resolve/resolv.conf",
 		"/lib/systemd/resolv.conf",
 		"/usr/lib/systemd/resolv.conf",
 	};
-	GFile *f;
-	GFileInfo *info;
-	gboolean ret = FALSE;
+	struct stat st, st_test;
+	guint i;
 
-	f = g_file_new_for_path (_PATH_RESCONF);
-	info = g_file_query_info (f,
-	                          G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK","\
-	                          G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
-	                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-	                          NULL, NULL);
+	if (lstat (_PATH_RESCONF, &st) != 0)
+		return FALSE;
 
-	if (info && g_file_info_get_is_symlink (info)) {
-		ret = nm_utils_strv_find_first ((gchar **) resolved_paths,
-		                                G_N_ELEMENTS (resolved_paths),
-		                                g_file_info_get_symlink_target (info)) >= 0;
-	}
+	if (S_ISLNK (st.st_mode)) {
+		gs_free char *full_path = NULL;
+		nm_auto_free char *real_path = NULL;
+
+		/* see if resolv.conf is a symlink with a target that is
+		 * exactly like one of the candidates.
+		 *
+		 * This check will work for symlinks, even if the target
+		 * does not exist and realpath() cannot resolve anything.
+		 *
+		 * We want to handle that, because systemd-resolved might not
+		 * have started yet. */
+		full_path = g_file_read_link (_PATH_RESCONF, NULL);
+		if (nm_utils_strv_find_first ((char **) RESOLVED_PATHS,
+		                              G_N_ELEMENTS (RESOLVED_PATHS),
+		                              full_path) >= 0)
+			return TRUE;
+
+		/* see if resolv.conf is a symlink that resolves exactly one
+		 * of the candidate paths.
+		 *
+		 * This check will work for symlinks that can be resolved
+		 * to a realpath, but the actual file might not exist.
+		 *
+		 * We want to handle that, because systemd-resolved might not
+		 * have started yet. */
+		real_path = realpath (_PATH_RESCONF, NULL);
+		if (nm_utils_strv_find_first ((char **) RESOLVED_PATHS,
+		                              G_N_ELEMENTS (RESOLVED_PATHS),
+		                              real_path) >= 0)
+			return TRUE;
 
-	g_clear_object(&info);
-	g_clear_object(&f);
+		/* fall-through and resolve the symlink, to check the file
+		 * it points to (below).
+		 *
+		 * This check is the most reliable, but it only works if
+		 * systemd-resolved already started and created the file. */
+		if (stat (_PATH_RESCONF, &st) != 0)
+			return FALSE;
+	}
+
+	/* see if resolv.conf resolves to one of the candidate
+	 * paths (or whether it is hard-linked). */
+	for (i = 0; i < G_N_ELEMENTS (RESOLVED_PATHS); i++) {
+		if (   stat (RESOLVED_PATHS[i], &st_test) == 0
+		    && st.st_dev == st_test.st_dev
+		    && st.st_ino == st_test.st_ino)
+			return TRUE;
+	}
 
-	return ret;
+	return FALSE;
 }
 
 static void
diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c
index fce1fef1..315f2c4d 100644
--- a/src/dns/nm-dns-systemd-resolved.c
+++ b/src/dns/nm-dns-systemd-resolved.c
@@ -136,81 +136,75 @@ add_interface_configuration (NMDnsSystemdResolved *self,
 }
 
 static void
-add_domain (GVariantBuilder *domains,
-            const char *domain,
-            gboolean never_default)
-{
-	/* If this link is never the default (e.g. only used for resources on this
-	 * network) add a routing domain. */
-	g_variant_builder_add (domains, "(sb)", domain, never_default);
-}
-
-static void
-update_add_ip6_config (NMDnsSystemdResolved *self,
-                       GVariantBuilder *dns,
-                       GVariantBuilder *domains,
-                       const NMIP6Config *config)
+update_add_ip_config (NMDnsSystemdResolved *self,
+                      GVariantBuilder *dns,
+                      GVariantBuilder *domains,
+                      gpointer config)
 {
+	int addr_family;
+	gsize addr_size;
 	guint i, n;
+	gboolean route_only;
 
-	n = nm_ip6_config_get_num_nameservers (config);
-	for (i = 0 ; i < n; i++) {
-		const struct in6_addr *ip;
-
-		g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)"));
-		g_variant_builder_add (dns, "i", AF_INET6);
-		ip = nm_ip6_config_get_nameserver (config, i),
-
-		g_variant_builder_add_value (dns, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, ip, 16, 1));
-		g_variant_builder_close (dns);
-	}
-
-	n = nm_ip6_config_get_num_searches (config);
-	if (n > 0) {
-		for (i = 0; i < n; i++) {
-			add_domain (domains, nm_ip6_config_get_search (config, i),
-			            nm_ip6_config_get_never_default (config));
-		}
-	} else {
-		n = nm_ip6_config_get_num_domains (config);
-		for (i = 0; i < n; i++) {
-			add_domain (domains, nm_ip6_config_get_domain (config, i),
-			            nm_ip6_config_get_never_default (config));
-		}
-	}
-}
+	if (NM_IS_IP4_CONFIG (config))
+		addr_family = AF_INET;
+	else if (NM_IS_IP6_CONFIG (config))
+		addr_family = AF_INET6;
+	else
+		g_return_if_reached ();
 
-static void
-update_add_ip4_config (NMDnsSystemdResolved *self,
-                       GVariantBuilder *dns,
-                       GVariantBuilder *domains,
-                       const NMIP4Config *config)
-{
-	guint i, n;
+	addr_size = nm_utils_addr_family_to_size (addr_family);
 
-	n = nm_ip4_config_get_num_nameservers (config);
+	n =   addr_family == AF_INET
+	    ? nm_ip4_config_get_num_nameservers (config)
+	    : nm_ip6_config_get_num_nameservers (config);
 	for (i = 0 ; i < n; i++) {
-		guint32 ns;
+		in_addr_t ns4;
+		gconstpointer ns;
 
-		g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)"));
-		g_variant_builder_add (dns, "i", AF_INET);
-		ns = nm_ip4_config_get_nameserver (config, i),
+		if (addr_family == AF_INET) {
+			ns4 = nm_ip4_config_get_nameserver (config, i);
+			ns = &ns4;
+		} else
+			ns = nm_ip6_config_get_nameserver (config, i);
 
-		g_variant_builder_add_value (dns, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &ns, 4, 1));
+		g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)"));
+		g_variant_builder_add (dns, "i", addr_family);
+		g_variant_builder_add_value (dns,
+		                             g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+		                                                        ns,
+		                                                        addr_size,
+		                                                        1));
 		g_variant_builder_close (dns);
 	}
 
-	n = nm_ip4_config_get_num_searches (config);
+	/* If this link is never the default (e.g. only used for resources on this
+	 * network) add a routing domain. */
+	route_only =   addr_family == AF_INET
+	             ? !nm_ip4_config_best_default_route_get (config)
+	             : !nm_ip6_config_best_default_route_get (config);
+
+	n =   addr_family == AF_INET
+	    ? nm_ip4_config_get_num_searches (config)
+	    : nm_ip6_config_get_num_searches (config);
 	if (n  > 0) {
 		for (i = 0; i < n; i++) {
-			add_domain (domains, nm_ip4_config_get_search (config, i),
-			            nm_ip4_config_get_never_default (config));
+			g_variant_builder_add (domains, "(sb)",
+			                       addr_family == AF_INET
+			                         ? nm_ip4_config_get_search (config, i)
+			                         : nm_ip6_config_get_search (config, i),
+			                       route_only);
 		}
 	} else {
-		n = nm_ip4_config_get_num_domains (config);
+		n =   addr_family == AF_INET
+		    ? nm_ip4_config_get_num_domains (config)
+		    : nm_ip6_config_get_num_domains (config);
 		for (i = 0; i < n; i++) {
-			add_domain (domains, nm_ip4_config_get_domain (config, i),
-			            nm_ip4_config_get_never_default (config));
+			g_variant_builder_add (domains, "(sb)",
+			                       addr_family == AF_INET
+			                         ? nm_ip4_config_get_domain (config, i)
+			                         : nm_ip6_config_get_domain (config, i),
+			                       route_only);
 		}
 	}
 }
@@ -243,14 +237,9 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic)
 	g_variant_builder_add (&domains, "i", ic->ifindex);
 	g_variant_builder_open (&domains, G_VARIANT_TYPE ("a(sb)"));
 
-	for (l = ic->configs ; l != NULL ; l = g_list_next (l)) {
-		if (NM_IS_IP4_CONFIG (l->data))
-			update_add_ip4_config (self, &dns, &domains, l->data);
-		else if (NM_IS_IP6_CONFIG (l->data))
-			update_add_ip6_config (self, &dns, &domains, l->data);
-		else
-			g_assert_not_reached ();
-	}
+	for (l = ic->configs; l; l = l->next)
+		update_add_ip_config (self, &dns, &domains, l->data);
+
 	g_variant_builder_close (&dns);
 	g_variant_builder_close (&domains);