dns: better detect systemd-resolved when checking for resolv.conf symlink

We autodetect systemd-resolved based on whether /etc/resolv.conf points
to one of the well known files of systemd-resolved.

Extend the check by also
 - follow symlinks and compare the absolute link target
 - open the file and compare the inodes for hard-linking

Note that when NetworkManager starts, systemd-resolved might not
have started yet. So, while comparing the inode is the best check,
we also compare symlinks (g_file_read_link() and realpath()).

Based-on-patch-by: Sam Morris <sam@robots.org.uk>

https://github.com/NetworkManager/NetworkManager/pull/16
https://bugzilla.gnome.org/show_bug.cgi?id=779269
This commit is contained in:
Thomas Haller 2017-05-11 13:30:26 +02:00
parent e70dfb4df7
commit fae84b16f8

View file

@ -1642,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;
/* 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;
}
g_clear_object(&info);
g_clear_object(&f);
/* 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