about summary refs log tree commit diff
path: root/src/dns/nm-dns-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/nm-dns-manager.c')
-rw-r--r--src/dns/nm-dns-manager.c88
1 files changed, 66 insertions, 22 deletions
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