dns: add new "rc-manager=auto" mode

Add a new `main.rc-manager=auto` setting, that favours to use
systemd-resolved (and not touch "/etc/resolv.conf" but configure
it via D-Bus), or falls back to `resolvconf`/`netconfig` binaries
if they are installed and enabled at compile time.
As final fallback use "symlink", like before.

Note that on Fedora there is no "openresolv" package ([1]). Instead, "systemd"
package provides "/usr/sbin/resolvconf" as a wrapper for systemd-resolved's
"resolvectl". On such a system the fallback to resolvconf is always
wrong, because NetworkManager should either talk to systemd-resolved
directly or not but never call "/usr/sbin/resolvconf". So, the special handling
for resolvconf and netconfig is only done if NetworkManager was build with these
applications explicitly enabled.

Note that SUSE builds NetworkManager with

    --with-netconfig=yes
    --with-config-dns-rc-manager-default=netconfig

and the new option won't be used there either. But of course, netconfig
already does all the right things on SUSE.

[1] https://bugzilla.redhat.com/show_bug.cgi?id=668153

Suggested-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Thomas Haller
2020-08-07 19:43:35 +02:00
parent c752c52b76
commit c1f9a0fff1
8 changed files with 121 additions and 45 deletions

8
NEWS
View File

@@ -8,6 +8,14 @@ The API is subject to change and not guaranteed to be compatible
with the later release.
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
* Introduce new "rc-manager=auto" setting and make it the default,
unless a different default is chosen at compile time.
This mode tries to detect "systemd-resolved", "resolvconf", and "netconfig"
and chooses the mode that seems most suitable depending on build
setting and runtime detection.
"resolvconf" and "netconfig" are only considered iff NetworkManager
was built with the respective options enabled.
=============================================
NetworkManager-1.26
Overview of changes since NetworkManager-1.24

View File

@@ -891,14 +891,15 @@ AC_SUBST(NM_CONFIG_DEFAULT_MAIN_DHCP, $config_dhcp_default)
AC_ARG_WITH(resolvconf, AS_HELP_STRING([--with-resolvconf=yes|no|path], [Enable resolvconf support]))
AC_ARG_WITH(netconfig, AS_HELP_STRING([--with-netconfig=yes|no], [Enable SUSE netconfig support]))
AC_ARG_WITH(config-dns-rc-manager-default, AS_HELP_STRING([--with-config-dns-rc-manager-default=symlink|file|netconfig|resolvconf], [Configure default value for main.rc-manager setting]), [config_dns_rc_manager_default=$withval])
AC_ARG_WITH(config-dns-rc-manager-default, AS_HELP_STRING([--with-config-dns-rc-manager-default=auto|symlink|file|netconfig|resolvconf], [Configure default value for main.rc-manager setting]), [config_dns_rc_manager_default=$withval])
if test "$config_dns_rc_manager_default" != "" -a \
"$config_dns_rc_manager_default" != auto -a \
"$config_dns_rc_manager_default" != file -a \
"$config_dns_rc_manager_default" != symlink -a \
"$config_dns_rc_manager_default" != netconfig -a \
"$config_dns_rc_manager_default" != resolvconf; then
AC_MSG_WARN([Unknown --with-config-dns-rc-manager-default=$config_dns_rc_manager_default setting.])
config_dns_rc_manager_default=
config_dns_rc_manager_default=auto
fi
# Use netconfig by default on SUSE
AS_IF([test -z "$with_netconfig" -a -f /etc/SuSE-release], with_netconfig=yes)
@@ -912,9 +913,6 @@ if test "$with_resolvconf" = "yes"; then
AC_MSG_ERROR(cannot find resolvconf in path. Set the path explicitly via --with-resolvconf=PATH.)
fi
fi
if test "$with_resolvconf" != "no"; then
AS_IF([test -z "$config_dns_rc_manager_default"], config_dns_rc_manager_default=resolvconf)
fi
if test "$with_netconfig" = "yes"; then
AC_PATH_PROGS(with_netconfig, netconfig, yes, /sbin:/usr/sbin:/usr/local/sbin)
@@ -922,11 +920,6 @@ if test "$with_netconfig" = "yes"; then
AC_MSG_ERROR(cannot find netconfig in path. Set the path explicitly via --with-netconfig=PATH.)
fi
fi
if test "$with_netconfig" != "no"; then
AS_IF([test -z "$config_dns_rc_manager_default"], config_dns_rc_manager_default=netconfig)
fi
AS_IF([test -z "$config_dns_rc_manager_default"], config_dns_rc_manager_default=symlink)
if test "$with_resolvconf" != "no"; then
AC_DEFINE_UNQUOTED(RESOLVCONF_PATH, "$with_resolvconf", [Path to resolvconf])

View File

@@ -115,7 +115,11 @@
%if 0%{?fedora} || 0%{?rhel} > 7
%global logging_backend_default journal
%if 0%{?fedora} || 0%{?rhel} > 8
%global dns_rc_manager_default auto
%else
%global dns_rc_manager_default symlink
%endif
%else
%global logging_backend_default syslog
%global dns_rc_manager_default file
@@ -641,6 +645,8 @@ This tool is still experimental.
%endif
-Ddist_version=%{version}-%{release} \
-Dconfig_plugins_default=%{config_plugins_default} \
-Dresolvconf=no \
-Dnetconfig=no \
-Dconfig_dns_rc_manager_default=%{dns_rc_manager_default} \
-Dconfig_logging_backend_default=%{logging_backend_default} \
-Djson_validation=true
@@ -779,6 +785,8 @@ intltoolize --automake --copy --force
%endif
--with-dist-version=%{version}-%{release} \
--with-config-plugins-default=%{config_plugins_default} \
--with-resolvconf=no \
--with-netconfig=no \
--with-config-dns-rc-manager-default=%{dns_rc_manager_default} \
--with-config-logging-backend-default=%{logging_backend_default} \
--enable-json-validation

View File

@@ -158,7 +158,7 @@ if [[ $NO_DIST != 1 ]]; then
--enable-polkit=yes \
--with-nm-cloud-setup=yes \
--with-config-dhcp-default=internal \
--with-config-dns-rc-manager-default=symlink \
--with-config-dns-rc-manager-default=auto \
|| die "Error autogen.sh"
if [[ $QUICK == 1 ]]; then
make dist -j 7 || die "Error make dist"

View File

@@ -309,7 +309,8 @@ no-auto-default=*
</para>
<para><literal>default</literal>: NetworkManager will update
<filename>/etc/resolv.conf</filename> to reflect the nameservers
provided by currently active connections.</para>
provided by currently active connections. The <literal>rc-manager</literal>
setting (below) controls how this is done.</para>
<para><literal>dnsmasq</literal>: NetworkManager will run
dnsmasq as a local caching nameserver, using "Conditional Forwarding"
if you are connected to a VPN, and then update
@@ -349,37 +350,57 @@ no-auto-default=*
<varlistentry>
<term><varname>rc-manager</varname></term>
<listitem><para>Set the <filename>resolv.conf</filename>
management mode. The default value depends on NetworkManager build
options, and this version of NetworkManager was build with a default of
"<literal>&NM_CONFIG_DEFAULT_MAIN_RC_MANAGER;</literal>".
Regardless of this setting, NetworkManager will
always write resolv.conf to its runtime state directory
<filename>&nmrundir;/resolv.conf</filename>.</para>
<listitem>
<para>Set the <filename>resolv.conf</filename>
management mode. This option is about how NetworkManager writes to
<filename>/etc/resolv.conf</filename>, if at all.
The default value depends on NetworkManager build
options, and this version of NetworkManager was build with a default of
"<literal>&NM_CONFIG_DEFAULT_MAIN_RC_MANAGER;</literal>".
Regardless of this setting, NetworkManager will
always write its version of resolv.conf to its runtime state directory
as <filename>&nmrundir;/resolv.conf</filename>.
</para>
<para>If you configure <literal>dns=none</literal> or make <filename>/etc/resolv.conf</filename>
immutable with <literal>chattr +i</literal>, NetworkManager will ignore this setting and
always choose <literal>unmanaged</literal> (below).
</para>
<para><literal>auto</literal>: if systemd-resolved plugin is configured via
the <literal>dns</literal> setting or if it gets detected as main DNS plugin,
NetworkManager will update systemd-resolved without touching <filename>/etc/resolv.conf</filename>.
Alternatively, if <literal>resolvconf</literal> or <literal>netconfig</literal> are enabled
at compile time and the respective binary is found, NetworkManager will automatically use it.
Note that if you install or uninstall these binaries, you need to reload the
<literal>rc-manager</literal> setting with SIGHUP or
<literal>systemctl reload NetworkManager</literal>. As last fallback
it uses the <literal>symlink</literal> option (see next).
</para>
<para><literal>symlink</literal>: If <filename>/etc/resolv.conf</filename> is
a regular file, NetworkManager will replace the file on update. If
<filename>/etc/resolv.conf</filename> is instead a symlink, NetworkManager
will leave it alone. Unless the symlink points to the internal file
<filename>&nmrundir;/resolv.conf</filename>,
in which case the symlink will be updated to emit an inotify notification.
This allows the user to conveniently instruct NetworkManager not
to manage <filename>/etc/resolv.conf</filename> by replacing it with
a symlink.</para>
a regular file or does not exist, NetworkManager will write the file directly.
If <filename>/etc/resolv.conf</filename> is instead a symlink, NetworkManager
will leave it alone. Unless the symlink points to the internal file
<filename>&nmrundir;/resolv.conf</filename>,
in which case the symlink will be updated to emit an inotify notification.
This allows the user to conveniently instruct NetworkManager not
to manage <filename>/etc/resolv.conf</filename> by replacing it with
a symlink.
</para>
<para><literal>file</literal>: NetworkManager will write
<filename>/etc/resolv.conf</filename> as file. If it finds
a symlink to an existing target, it will follow the symlink and
update the target instead. In no case will an existing symlink
be replaced by a file. Note that older versions of NetworkManager
behaved differently and would replace dangling symlinks with a
plain file.</para>
<filename>/etc/resolv.conf</filename> as regular file. If it finds
a symlink to an existing target, it will follow the symlink and
update the target instead. In no case will an existing symlink
be replaced by a file. Note that older versions of NetworkManager
behaved differently and would replace dangling symlinks with a
plain file.
</para>
<para><literal>resolvconf</literal>: NetworkManager will run
resolvconf to update the DNS configuration.</para>
resolvconf to update the DNS configuration.</para>
<para><literal>netconfig</literal>: NetworkManager will run
netconfig to update the DNS configuration.</para>
netconfig to update the DNS configuration.</para>
<para><literal>unmanaged</literal>: don't touch
<filename>/etc/resolv.conf</filename>.</para>
<filename>/etc/resolv.conf</filename>.</para>
<para><literal>none</literal>: deprecated alias for
<literal>symlink</literal>.</para>
<literal>symlink</literal>.</para>
</listitem>
</varlistentry>

View File

@@ -49,7 +49,7 @@ option('ifupdown', type: 'boolean', value: false, description: 'enable ifupdown
# handlers for resolv.conf
option('resolvconf', type: 'string', value: '', description: 'Enable resolvconf support')
option('netconfig', type: 'string', value: '', description: 'Enable SUSE netconfig support')
option('config_dns_rc_manager_default', type: 'combo', choices: ['symlink', 'file', 'netconfig', 'resolvconf'], value: 'symlink', description: 'Configure default value for main.rc-manager setting')
option('config_dns_rc_manager_default', type: 'combo', choices: ['auto', 'symlink', 'file', 'netconfig', 'resolvconf'], value: 'auto', description: 'Configure default value for main.rc-manager setting')
# dhcp clients
option('dhclient', type: 'string', value: '', description: 'Enable dhclient support')

View File

@@ -42,10 +42,16 @@
#ifndef RESOLVCONF_PATH
#define RESOLVCONF_PATH "/sbin/resolvconf"
#define HAS_RESOLVCONF 0
#else
#define HAS_RESOLVCONF 1
#endif
#ifndef NETCONFIG_PATH
#define NETCONFIG_PATH "/sbin/netconfig"
#define HAS_NETCONFIG 0
#else
#define HAS_NETCONFIG 1
#endif
/*****************************************************************************/
@@ -182,6 +188,7 @@ domain_is_routing (const char *domain)
static
NM_UTILS_LOOKUP_STR_DEFINE (_rc_manager_to_string, NMDnsManagerResolvConfManager,
NM_UTILS_LOOKUP_DEFAULT_WARN (NULL),
NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO, "auto"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN, "unknown"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, "unmanaged"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE, "immutable"),
@@ -1900,6 +1907,7 @@ _check_resconf_immutable (NMDnsManagerResolvConfManager rc_manager)
case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE:
case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF:
case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG:
case NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO:
break;
}
}
@@ -1999,6 +2007,7 @@ init_resolv_conf_mode (NMDnsManager *self, gboolean force_reload_plugin)
gboolean param_changed = FALSE;
gboolean plugin_changed = FALSE;
gboolean systemd_resolved_changed = FALSE;
gboolean rc_manager_was_auto = FALSE;
mode = nm_config_data_get_dns_mode (nm_config_get_data (priv->config));
systemd_resolved = nm_config_data_get_systemd_resolved (nm_config_get_data (priv->config));
@@ -2014,7 +2023,9 @@ init_resolv_conf_mode (NMDnsManager *self, gboolean force_reload_plugin)
again:
if (!man) {
/* nop */
} else if (NM_IN_STRSET (man, "symlink", "none"))
} else if (nm_streq (man, "auto"))
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO;
else if (NM_IN_STRSET (man, "symlink", "none"))
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK;
else if (nm_streq (man, "file"))
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE;
@@ -2031,7 +2042,7 @@ again:
man, ""NM_CONFIG_DEFAULT_MAIN_RC_MANAGER);
}
man = ""NM_CONFIG_DEFAULT_MAIN_RC_MANAGER;
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK;
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO;
goto again;
}
}
@@ -2070,6 +2081,31 @@ again:
plugin_changed = TRUE;
}
if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO) {
rc_manager_was_auto = TRUE;
if (nm_streq (mode, "systemd-resolved"))
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED;
else if ( HAS_RESOLVCONF
&& g_file_test (RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE)) {
/* We detect /sbin/resolvconf only at this stage. That means, if you install
* or uninstall openresolv afterwards, you need to reload the DNS settings
* (with SIGHUP or `systemctl reload NetworkManager.service`).
*
* We only accept resolvconf if NetworkManager was built with --with-resolvconf.
* For example, on Fedora the systemd package provides a compat resolvconf
* implementation for systemd-resolved. But using that never makes sense, because
* there we either use full systemd-resolved mode or not. In no case does it
* make sense to call that resolvconf implementation. */
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF;
} else if ( HAS_NETCONFIG
&& g_file_test (NETCONFIG_PATH, G_FILE_TEST_IS_EXECUTABLE)) {
/* Like for resolvconf, we detect only once. We only autoenable this
* option, if NetworkManager was built with netconfig explicitly enabled. */
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG;
} else
rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK;
}
/* The systemd-resolved plugin is special. We typically always want to keep
* systemd-resolved up to date even if the configured plugin is different. */
if (systemd_resolved) {
@@ -2096,10 +2132,11 @@ again:
}
if (param_changed || plugin_changed || systemd_resolved_changed) {
_LOGI ("init: dns=%s%s rc-manager=%s%s%s%s",
_LOGI ("init: dns=%s%s rc-manager=%s%s%s%s%s",
mode,
(systemd_resolved ? ",systemd-resolved" : ""),
_rc_manager_to_string (rc_manager),
rc_manager_was_auto ? " (auto)" : "",
NM_PRINT_FMT_QUOTED (priv->plugin, ", plugin=",
nm_dns_plugin_get_name (priv->plugin), "", ""));
}

View File

@@ -88,12 +88,20 @@ void nm_dns_manager_set_hostname (NMDnsManager *self,
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED: do not touch /etc/resolv.conf
* (but still write the internal copy -- unless it is symlinked by
* /etc/resolv.conf)
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO: if /etc/resolv.conf is marked
* as an immutable file, use "unmanaged" and don't touch /etc/resolv.conf.
* Otherwise, if "systemd-resolved" is enabled (or detected), configure systemd-resolved via D-Bus
* and don't touch /etc/resolv.conf.
* Otherwise, if "resolvconf" application is found, use it.
* As last resort, fallback to "symlink" which writes to /etc/resolv.conf
* if (and only if) the file is missing or not a symlink.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE: similar to "unmanaged",
* but indicates that resolv.conf cannot be modified.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: NM writes resolv.conf
* by symlinking it to the run state directory.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: Like SYMLINK, but instead of
* symlinking /etc/resolv.conf, write it as a file.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: NM writes /etc/resolv.conf
* if the file is missing or not a symlink. An existing symlink is
* left untouched.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: Write to /etc/resolv.conf directly.
* If it is a file, write it as file, otherwise follow symlinks.
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: NM is managing resolv.conf
through resolvconf
* @NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: NM is managing resolv.conf
@@ -103,6 +111,7 @@ void nm_dns_manager_set_hostname (NMDnsManager *self,
*/
typedef enum {
NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN,
NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO,
NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE,
NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK,