From c1f9a0fff183f4e41349ed3879b409e757c181eb Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 7 Aug 2020 19:43:35 +0200 Subject: 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 --- NEWS | 8 ++++ configure.ac | 13 ++---- contrib/fedora/rpm/NetworkManager.spec | 8 ++++ contrib/fedora/rpm/build_clean.sh | 2 +- man/NetworkManager.conf.xml | 73 ++++++++++++++++++++++------------ meson_options.txt | 2 +- src/dns/nm-dns-manager.c | 43 ++++++++++++++++++-- src/dns/nm-dns-manager.h | 17 ++++++-- 8 files changed, 121 insertions(+), 45 deletions(-) diff --git a/NEWS b/NEWS index ca30fd033d..a9a0ea12f9 100644 --- a/NEWS +++ b/NEWS @@ -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 diff --git a/configure.ac b/configure.ac index d6842670a2..8f8b9338f0 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec index 20001c6fd7..343e291998 100644 --- a/contrib/fedora/rpm/NetworkManager.spec +++ b/contrib/fedora/rpm/NetworkManager.spec @@ -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 diff --git a/contrib/fedora/rpm/build_clean.sh b/contrib/fedora/rpm/build_clean.sh index 776e4c4df6..e7afdb4f24 100755 --- a/contrib/fedora/rpm/build_clean.sh +++ b/contrib/fedora/rpm/build_clean.sh @@ -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" diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index aac80a0878..ce61c8216d 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -309,7 +309,8 @@ no-auto-default=* default: NetworkManager will update /etc/resolv.conf to reflect the nameservers - provided by currently active connections. + provided by currently active connections. The rc-manager + setting (below) controls how this is done. dnsmasq: 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=* rc-manager - Set the resolv.conf - management mode. The default value depends on NetworkManager build - options, and this version of NetworkManager was build with a default of - "&NM_CONFIG_DEFAULT_MAIN_RC_MANAGER;". - Regardless of this setting, NetworkManager will - always write resolv.conf to its runtime state directory - &nmrundir;/resolv.conf. + + Set the resolv.conf + management mode. This option is about how NetworkManager writes to + /etc/resolv.conf, if at all. + The default value depends on NetworkManager build + options, and this version of NetworkManager was build with a default of + "&NM_CONFIG_DEFAULT_MAIN_RC_MANAGER;". + Regardless of this setting, NetworkManager will + always write its version of resolv.conf to its runtime state directory + as &nmrundir;/resolv.conf. + + If you configure dns=none or make /etc/resolv.conf + immutable with chattr +i, NetworkManager will ignore this setting and + always choose unmanaged (below). + + auto: if systemd-resolved plugin is configured via + the dns setting or if it gets detected as main DNS plugin, + NetworkManager will update systemd-resolved without touching /etc/resolv.conf. + Alternatively, if resolvconf or netconfig 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 + rc-manager setting with SIGHUP or + systemctl reload NetworkManager. As last fallback + it uses the symlink option (see next). + symlink: If /etc/resolv.conf is - a regular file, NetworkManager will replace the file on update. If - /etc/resolv.conf is instead a symlink, NetworkManager - will leave it alone. Unless the symlink points to the internal file - &nmrundir;/resolv.conf, - in which case the symlink will be updated to emit an inotify notification. - This allows the user to conveniently instruct NetworkManager not - to manage /etc/resolv.conf by replacing it with - a symlink. + a regular file or does not exist, NetworkManager will write the file directly. + If /etc/resolv.conf is instead a symlink, NetworkManager + will leave it alone. Unless the symlink points to the internal file + &nmrundir;/resolv.conf, + in which case the symlink will be updated to emit an inotify notification. + This allows the user to conveniently instruct NetworkManager not + to manage /etc/resolv.conf by replacing it with + a symlink. + file: NetworkManager will write - /etc/resolv.conf 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. + /etc/resolv.conf 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. + resolvconf: NetworkManager will run - resolvconf to update the DNS configuration. + resolvconf to update the DNS configuration. netconfig: NetworkManager will run - netconfig to update the DNS configuration. + netconfig to update the DNS configuration. unmanaged: don't touch - /etc/resolv.conf. + /etc/resolv.conf. none: deprecated alias for - symlink. + symlink. diff --git a/meson_options.txt b/meson_options.txt index d6306711ec..5bfa3b151e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -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') diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 9108911cbb..bc1b32f86b 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -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), "", "")); } diff --git a/src/dns/nm-dns-manager.h b/src/dns/nm-dns-manager.h index 2a0c9deee3..d82a68d154 100644 --- a/src/dns/nm-dns-manager.h +++ b/src/dns/nm-dns-manager.h @@ -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, -- cgit v1.2.1