From 5f9d348c2019753712ff7444e3a8ae5ac3f38dda Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 14 Apr 2015 08:55:01 +0200 Subject: dns: always write a private resolv.conf to runtime directory https://bugzilla.gnome.org/show_bug.cgi?id=747821 --- src/dns-manager/nm-dns-manager.c | 64 +++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index 490a4cd1db..628fee045f 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -452,13 +452,32 @@ dispatch_resolvconf (char **searches, static gboolean update_resolv_conf (char **searches, char **nameservers, - GError **error) + GError **error, + gboolean install_etc) { FILE *f; struct stat st; g_return_val_if_fail (error != NULL, FALSE); + /* If we are not managing /etc/resolv.conf and it points to + * MY_RESOLV_CONF, don't write the private DNS configuration to + * MY_RESOLV_CONF otherwise we would overwrite the changes done by + * some external application. + */ + if (!install_etc) { + char *path = g_file_read_link (_PATH_RESCONF, NULL); + gboolean ours = !g_strcmp0 (path, MY_RESOLV_CONF); + + g_free (path); + + if (ours) { + nm_log_dbg (LOGD_DNS, "not updating " MY_RESOLV_CONF + " since it points to " _PATH_RESCONF); + return FALSE; + } + } + if ((f = fopen (MY_RESOLV_CONF_TMP, "w")) == NULL) { g_set_error (error, NM_MANAGER_ERROR, @@ -498,6 +517,9 @@ update_resolv_conf (char **searches, return FALSE; } + if (!install_etc) + return TRUE; + /* Don't overwrite a symbolic link unless it points to MY_RESOLV_CONF. */ if (lstat (_PATH_RESCONF, &st) != -1) { /* Don't overwrite a symbolic link. */ @@ -654,18 +676,20 @@ update_dns (NMDnsManager *self, char **nameservers = NULL; char **nis_servers = NULL; int num, i, len; - gboolean success = FALSE, caching = FALSE; + gboolean success = FALSE, caching = FALSE, update = TRUE; g_return_val_if_fail (!error || !*error, FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); - if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) - return TRUE; - - priv->dns_touched = TRUE; - - nm_log_dbg (LOGD_DNS, "updating resolv.conf"); + if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) { + update = FALSE; + success = TRUE; + nm_log_dbg (LOGD_DNS, "not updating resolv.conf"); + } else { + priv->dns_touched = TRUE; + nm_log_dbg (LOGD_DNS, "updating resolv.conf"); + } /* Update hash with config we're applying */ compute_hash (self, priv->hash); @@ -754,7 +778,7 @@ update_dns (NMDnsManager *self, nis_domain = rc.nis_domain; /* Let any plugins do their thing first */ - if (priv->plugin) { + if (update && priv->plugin) { NMDnsPlugin *plugin = priv->plugin; const char *plugin_name = nm_dns_plugin_get_name (plugin); GSList *vpn_configs = NULL, *dev_configs = NULL, *other_configs = NULL; @@ -802,22 +826,28 @@ update_dns (NMDnsManager *self, nameservers[0] = g_strdup ("127.0.0.1"); } + if (update) { #ifdef RESOLVCONF_PATH - success = dispatch_resolvconf (searches, nameservers, error); + success = dispatch_resolvconf (searches, nameservers, error); #endif #ifdef NETCONFIG_PATH - if (success == FALSE) { - success = dispatch_netconfig (searches, nameservers, - nis_domain, nis_servers, error); - } + if (success == FALSE) { + success = dispatch_netconfig (searches, nameservers, + nis_domain, nis_servers, error); + } #endif + } - if (success == FALSE) - success = update_resolv_conf (searches, nameservers, error); + if (update && !success) { + success = update_resolv_conf (searches, nameservers, error, TRUE); + } else { + /* Only update private resolv.conf in NMRUNDIR, ignore errors */ + update_resolv_conf (searches, nameservers, error, FALSE); + } /* signal that resolv.conf was changed */ - if (success) + if (update && success) g_signal_emit (self, signals[CONFIG_CHANGED], 0); if (searches) -- cgit v1.2.1 From de0d623680d7dcf5a2653fccb4fa530985a1f52e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 20 Apr 2015 09:19:04 +0200 Subject: dns: don't fall back to other methods when resolvconf or netconfig fail --- src/dns-manager/nm-dns-manager.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index 628fee045f..1b75c91a6c 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -684,7 +684,6 @@ update_dns (NMDnsManager *self, if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) { update = FALSE; - success = TRUE; nm_log_dbg (LOGD_DNS, "not updating resolv.conf"); } else { priv->dns_touched = TRUE; @@ -827,24 +826,18 @@ update_dns (NMDnsManager *self, } if (update) { -#ifdef RESOLVCONF_PATH +#if defined(RESOLVCONF_PATH) success = dispatch_resolvconf (searches, nameservers, error); -#endif - -#ifdef NETCONFIG_PATH - if (success == FALSE) { - success = dispatch_netconfig (searches, nameservers, - nis_domain, nis_servers, error); - } +#elif defined(NETCONFIG_PATH) + success = dispatch_netconfig (searches, nameservers, nis_domain, + nis_servers, error); +#else + success = update_resolv_conf (searches, nameservers, error, TRUE); #endif } - if (update && !success) { - success = update_resolv_conf (searches, nameservers, error, TRUE); - } else { - /* Only update private resolv.conf in NMRUNDIR, ignore errors */ - update_resolv_conf (searches, nameservers, error, FALSE); - } + /* Only update private resolv.conf in NMRUNDIR, ignore errors */ + update_resolv_conf (searches, nameservers, error, FALSE); /* signal that resolv.conf was changed */ if (update && success) @@ -857,7 +850,7 @@ update_dns (NMDnsManager *self, if (nis_servers) g_strfreev (nis_servers); - return success; + return !update || success; } static void -- cgit v1.2.1 From e573977b808409ccb26562ca8536d46be701f833 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 20 Apr 2015 11:11:32 +0200 Subject: dns: allow runtime selection of resolv.conf manager Add a new 'rc-manager' configuration parameter that allows to select the strategy used to write resolv.conf; currently supported values are: none|resolvconf|netconfig, 'none' meaning that NM directly writes the file. The default value of the parameter is 'none'; however if a RESOLVCONF_PATH (or NETCONFIG_PATH) is specified at build time, the default value will be 'resolvconf' (or 'netconfig'). --- configure.ac | 4 +- src/dns-manager/nm-dns-manager.c | 94 ++++++++++++++++++++++++++++++++-------- src/dns-manager/nm-dns-manager.h | 16 +++++++ src/nm-config-data.c | 14 ++++++ src/nm-config-data.h | 2 + src/nm-config.c | 2 + 6 files changed, 111 insertions(+), 21 deletions(-) diff --git a/configure.ac b/configure.ac index 436db10cc7..0689fd526a 100644 --- a/configure.ac +++ b/configure.ac @@ -733,10 +733,10 @@ if test "$with_netconfig" = "yes"; then fi # Define resolvconf and netconfig paths if test "$with_resolvconf" != "no"; then - AC_DEFINE_UNQUOTED(RESOLVCONF_PATH, "$with_resolvconf", [Path to resolvconf (if enabled)]) + AC_DEFINE_UNQUOTED(RESOLVCONF_PATH, "$with_resolvconf", [Path to resolvconf]) fi if test "$with_netconfig" != "no"; then - AC_DEFINE_UNQUOTED(NETCONFIG_PATH, "$with_netconfig", [Path to netconfig (if enabled)]) + AC_DEFINE_UNQUOTED(NETCONFIG_PATH, "$with_netconfig", [Path to netconfig]) fi # iptables path diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index 1b75c91a6c..2e5fa814b3 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -72,6 +72,18 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT) #define HASH_LEN 20 +#ifdef RESOLVCONF_PATH +#define RESOLVCONF_SELECTED +#else +#define RESOLVCONF_PATH "/sbin/resolvconf" +#endif + +#ifdef NETCONFIG_PATH +#define NETCONFIG_SELECTED +#else +#define NETCONFIG_PATH "/sbin/netconfig" +#endif + typedef struct { NMIP4Config *ip4_vpn_config; NMIP4Config *ip4_device_config; @@ -85,6 +97,7 @@ typedef struct { guint8 prev_hash[HASH_LEN]; /* Hash when begin_updates() was called */ NMDnsManagerResolvConfMode resolv_conf_mode; + NMDnsManagerResolvConfManager rc_manager; NMDnsPlugin *plugin; NMConfig *config; @@ -223,10 +236,6 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src) } -#if defined(NETCONFIG_PATH) -/**********************************/ -/* SUSE */ - static GPid run_netconfig (GError **error, gint *stdin_fd) { @@ -328,8 +337,6 @@ dispatch_netconfig (char **searches, return ret > 0; } -#endif - static gboolean write_resolv_conf (FILE *f, @@ -390,7 +397,6 @@ write_resolv_conf (FILE *f, return retval; } -#ifdef RESOLVCONF_PATH static gboolean dispatch_resolvconf (char **searches, char **nameservers, @@ -443,7 +449,6 @@ dispatch_resolvconf (char **searches, return retval; } -#endif #define MY_RESOLV_CONF NMRUNDIR "/resolv.conf" #define MY_RESOLV_CONF_TMP MY_RESOLV_CONF ".tmp" @@ -826,18 +831,26 @@ update_dns (NMDnsManager *self, } if (update) { -#if defined(RESOLVCONF_PATH) - success = dispatch_resolvconf (searches, nameservers, error); -#elif defined(NETCONFIG_PATH) - success = dispatch_netconfig (searches, nameservers, nis_domain, - nis_servers, error); -#else - success = update_resolv_conf (searches, nameservers, error, TRUE); -#endif + switch (priv->rc_manager) { + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: + success = update_resolv_conf (searches, nameservers, error, TRUE); + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: + success = dispatch_resolvconf (searches, nameservers, error); + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: + success = dispatch_netconfig (searches, nameservers, nis_domain, + nis_servers, error); + break; + default: + g_assert_not_reached (); + } } - /* Only update private resolv.conf in NMRUNDIR, ignore errors */ - update_resolv_conf (searches, nameservers, error, FALSE); + /* Unless we've already done it, update private resolv.conf in NMRUNDIR + ignoring any errors */ + if (!(update && priv->rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE)) + update_resolv_conf (searches, nameservers, error, FALSE); /* signal that resolv.conf was changed */ if (update && success) @@ -1175,6 +1188,46 @@ init_resolv_conf_mode (NMDnsManager *self) } } +static void +init_resolv_conf_manager (NMDnsManager *self) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + const char *man, *desc = ""; + + man = nm_config_data_get_rc_manager (nm_config_get_data (priv->config)); + if (!g_strcmp0 (man, "none")) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE; + else if (!g_strcmp0 (man, "resolvconf")) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF; + else if (!g_strcmp0 (man, "netconfig")) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG; + else { +#if defined(RESOLVCONF_SELECTED) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF; +#elif defined(NETCONFIG_SELECTED) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG; +#else + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE; +#endif + if (man) + nm_log_warn (LOGD_DNS, "DNS: unknown resolv.conf manager '%s'", man); + } + + switch (priv->rc_manager) { + case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: + desc = "resolvconf"; + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: + desc = "netconfig"; + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: + desc = "none"; + break; + } + + nm_log_info (LOGD_DNS, "DNS: using resolv.conf manager '%s'", desc); +} + static void config_changed_cb (NMConfig *config, NMConfigData *config_data, @@ -1184,10 +1237,12 @@ config_changed_cb (NMConfig *config, { GError *error = NULL; - if (!(changes & NM_CONFIG_CHANGE_DNS_MODE)) + if (!NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_DNS_MODE | + NM_CONFIG_CHANGE_RC_MANAGER)) return; init_resolv_conf_mode (self); + init_resolv_conf_manager (self); if (!update_dns (self, TRUE, &error)) { nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); g_clear_error (&error); @@ -1208,6 +1263,7 @@ nm_dns_manager_init (NMDnsManager *self) G_CALLBACK (config_changed_cb), self); init_resolv_conf_mode (self); + init_resolv_conf_manager (self); } static void diff --git a/src/dns-manager/nm-dns-manager.h b/src/dns-manager/nm-dns-manager.h index bc374fcf5f..a3e6cb2699 100644 --- a/src/dns-manager/nm-dns-manager.h +++ b/src/dns-manager/nm-dns-manager.h @@ -99,6 +99,22 @@ typedef enum { NM_DNS_MANAGER_RESOLV_CONF_PROXY } NMDnsManagerResolvConfMode; +/** + * NMDnsManagerResolvConfManager + * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: NM directly writes resolv.conf + * @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 + through netconfig + * + * NMDnsManager's management of resolv.conf + */ +typedef enum { + NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE, + NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, + NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, +} NMDnsManagerResolvConfManager; + NMDnsManagerResolvConfMode nm_dns_manager_get_resolv_conf_mode (NMDnsManager *mgr); G_END_DECLS diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 45d90b51d2..a987a8f3ef 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -44,6 +44,7 @@ typedef struct { } no_auto_default; char *dns_mode; + char *rc_manager; } NMConfigDataPrivate; @@ -138,6 +139,14 @@ nm_config_data_get_dns_mode (const NMConfigData *self) return NM_CONFIG_DATA_GET_PRIVATE (self)->dns_mode; } +const char * +nm_config_data_get_rc_manager (const NMConfigData *self) +{ + g_return_val_if_fail (self, NULL); + + return NM_CONFIG_DATA_GET_PRIVATE (self)->rc_manager; +} + /************************************************************************/ static gboolean @@ -205,6 +214,9 @@ nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data) if (g_strcmp0 (nm_config_data_get_dns_mode (old_data), nm_config_data_get_dns_mode (new_data))) changes |= NM_CONFIG_CHANGE_DNS_MODE; + if (g_strcmp0 (nm_config_data_get_rc_manager (old_data), nm_config_data_get_rc_manager (new_data))) + changes |= NM_CONFIG_CHANGE_RC_MANAGER; + return changes; } @@ -300,6 +312,7 @@ finalize (GObject *gobject) g_strfreev (priv->no_auto_default.arr); g_free (priv->dns_mode); + g_free (priv->rc_manager); g_key_file_unref (priv->keyfile); @@ -325,6 +338,7 @@ constructed (GObject *object) priv->connectivity.interval = MAX (0, interval); priv->dns_mode = g_key_file_get_value (priv->keyfile, "main", "dns", NULL); + priv->rc_manager = g_key_file_get_value (priv->keyfile, "main", "rc-manager", NULL); G_OBJECT_CLASS (nm_config_data_parent_class)->constructed (object); } diff --git a/src/nm-config-data.h b/src/nm-config-data.h index f260a73a90..50c53995ad 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -52,6 +52,7 @@ typedef enum { /*< flags >*/ NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 2), NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 3), NM_CONFIG_CHANGE_DNS_MODE = (1L << 4), + NM_CONFIG_CHANGE_RC_MANAGER = (1L << 5), _NM_CONFIG_CHANGE_LAST, NM_CONFIG_CHANGE_ALL = ((_NM_CONFIG_CHANGE_LAST - 1) << 1) - 1, @@ -88,6 +89,7 @@ const char *const*nm_config_data_get_no_auto_default (const NMConfigData *config const GSList * nm_config_data_get_no_auto_default_list (const NMConfigData *config_data); const char *nm_config_data_get_dns_mode (const NMConfigData *self); +const char *nm_config_data_get_rc_manager (const NMConfigData *self); G_END_DECLS diff --git a/src/nm-config.c b/src/nm-config.c index 3dbe58fb90..8e8100fe89 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -738,6 +738,8 @@ _change_flags_one_to_string (NMConfigChangeFlags flag) return "no-auto-default"; case NM_CONFIG_CHANGE_DNS_MODE: return "dns-mode"; + case NM_CONFIG_CHANGE_RC_MANAGER: + return "rc-manager"; default: g_return_val_if_reached ("unknown"); } -- cgit v1.2.1 From b1a81e5165e21eec82a68a3aece24027d58f5330 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 20 Apr 2015 14:45:09 +0200 Subject: man: document 'rc-manager' option --- man/NetworkManager.conf.xml.in | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index ae4ba88fd6..7807b1bf9d 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -253,6 +253,20 @@ no-auto-default=* + + rc-manager + Set the resolv.conf + management mode. The default value depends on how NetworkManager + was built. + none: NetworkManager will directly + write changes to resolv.conf. + resolvconf: NetworkManager will run + resolvconf to update the DNS configuration. + netconfig: NetworkManager will run + netconfig to update the DNS configuration. + + + debug Comma separated list of options to aid -- cgit v1.2.1