diff options
Diffstat (limited to 'src/dns-manager')
| -rw-r--r-- | src/dns-manager/nm-dns-dnsmasq.c | 15 | ||||
| -rw-r--r-- | src/dns-manager/nm-dns-manager.c | 224 | ||||
| -rw-r--r-- | src/dns-manager/nm-dns-plugin.c | 6 | ||||
| -rw-r--r-- | src/dns-manager/nm-dns-unbound.c | 2 | ||||
| -rw-r--r-- | src/dns-manager/nm-dns-utils.c | 2 |
5 files changed, 143 insertions, 106 deletions
diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c index 63e37bf3..8663dfd8 100644 --- a/src/dns-manager/nm-dns-dnsmasq.c +++ b/src/dns-manager/nm-dns-dnsmasq.c @@ -18,7 +18,7 @@ * */ -#include "config.h" +#include "nm-default.h" #include <stdlib.h> #include <unistd.h> @@ -27,7 +27,6 @@ #include <arpa/inet.h> #include <sys/stat.h> -#include "nm-default.h" #include "nm-dns-dnsmasq.h" #include "nm-utils.h" #include "nm-ip4-config.h" @@ -145,15 +144,15 @@ add_global_config (GString *str, const NMGlobalDnsConfig *config) for (i = 0; i < nm_global_dns_config_get_num_domains (config); i++) { NMGlobalDnsDomain *domain = nm_global_dns_config_get_domain (config, i); const char *const *servers = nm_global_dns_domain_get_servers (domain); + const char *name = nm_global_dns_domain_get_name (domain); + + g_return_if_fail (name); for (j = 0; servers && servers[j]; j++) { - if (!strcmp (servers[j], "*")) + if (!strcmp (name, "*")) g_string_append_printf (str, "server=%s\n", servers[j]); - else { - g_string_append_printf (str, "server=/%s/%s\n", - nm_global_dns_domain_get_name (domain), - servers[j]); - } + else + g_string_append_printf (str, "server=/%s/%s\n", name, servers[j]); } } diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index 01e8bf1d..79d345be 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -21,7 +21,7 @@ * and others */ -#include "config.h" +#include "nm-default.h" #include <errno.h> #include <fcntl.h> @@ -35,7 +35,6 @@ #include <linux/fs.h> -#include "nm-default.h" #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-dns-manager.h" @@ -82,6 +81,10 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT) #define NETCONFIG_PATH "/sbin/netconfig" #endif +#define PLUGIN_RATELIMIT_INTERVAL 30 +#define PLUGIN_RATELIMIT_BURST 5 +#define PLUGIN_RATELIMIT_DELAY 300 + NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager); /*********************************************************************************************/ @@ -130,6 +133,12 @@ typedef struct { NMConfig *config; gboolean dns_touched; + + struct { + guint64 ts; + guint num_restarts; + guint timer; + } plugin_ratelimit; } NMDnsManagerPrivate; enum { @@ -357,7 +366,6 @@ dispatch_netconfig (NMDnsManager *self, if (searches) { str = g_strjoinv (" ", searches); - write_to_netconfig (self, fd, "DNSSEARCH", str); g_free (str); } @@ -405,10 +413,9 @@ write_resolv_conf (FILE *f, char **options, GError **error) { - char *searches_str = NULL; - char *nameservers_str = NULL; - char *options_str = NULL; - gboolean retval = FALSE; + gs_free char *searches_str = NULL; + gs_free char *nameservers_str = NULL; + gs_free char *options_str = NULL; char *tmp_str; GString *str; int i; @@ -425,11 +432,10 @@ write_resolv_conf (FILE *f, g_free (tmp_str); } - str = g_string_new (""); - if (nameservers) { int num = g_strv_length (nameservers); + str = g_string_new (""); for (i = 0; i < num; i++) { if (i == 3) { g_string_append (str, "# "); @@ -443,28 +449,22 @@ write_resolv_conf (FILE *f, g_string_append (str, nameservers[i]); g_string_append_c (str, '\n'); } + nameservers_str = g_string_free (str, FALSE); } - nameservers_str = g_string_free (str, FALSE); - if (fprintf (f, "# Generated by NetworkManager\n%s%s%s", searches_str ? searches_str : "", - nameservers_str, - options_str ? options_str : "") > 0) - retval = TRUE; - else { + nameservers_str ? nameservers_str : "", + options_str ? options_str : "") < 0) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not write " _PATH_RESCONF ": %s\n", + "Could not write " _PATH_RESCONF ": %s", g_strerror (errno)); + return FALSE; } - g_free (searches_str); - g_free (nameservers_str); - g_free (options_str); - - return retval; + return TRUE; } static SpawnResult @@ -474,9 +474,9 @@ dispatch_resolvconf (NMDnsManager *self, char **options, GError **error) { - char *cmd; + gs_free char *cmd = NULL; FILE *f; - gboolean retval = FALSE; + gboolean success = FALSE; int errnosv, err; if (!g_file_test (RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE)) { @@ -487,39 +487,46 @@ dispatch_resolvconf (NMDnsManager *self, return SR_NOTFOUND; } - if (searches || nameservers) { - cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); - _LOGI ("Writing DNS information to %s", RESOLVCONF_PATH); - if ((f = popen (cmd, "w")) == NULL) - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not write to %s: %s\n", - RESOLVCONF_PATH, - g_strerror (errno)); - else { - retval = write_resolv_conf (f, searches, nameservers, options, error); - err = pclose (f); - if (err < 0) { - errnosv = errno; - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errnosv), - "Failed to close pipe to resolvconf: %d", errnosv); - retval = FALSE; - } else if (err > 0) { - _LOGW ("resolvconf failed with status %d", err); - retval = FALSE; - } - } - } else { - cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL); + if (!searches && !nameservers) { _LOGI ("Removing DNS information from %s", RESOLVCONF_PATH); - if (nm_spawn_process (cmd, error) == 0) - retval = TRUE; + + cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL); + if (nm_spawn_process (cmd, error) != 0) + return SR_ERROR; + + return SR_SUCCESS; + } + + _LOGI ("Writing DNS information to %s", RESOLVCONF_PATH); + + cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); + if ((f = popen (cmd, "w")) == NULL) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not write to %s: %s", + RESOLVCONF_PATH, + g_strerror (errno)); + return SR_ERROR; } - g_free (cmd); + success = write_resolv_conf (f, searches, nameservers, options, error); + err = pclose (f); + if (err < 0) { + errnosv = errno; + g_clear_error (error); + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errnosv), + "Failed to close pipe to resolvconf: %d", errnosv); + return SR_ERROR; + } else if (err > 0) { + _LOGW ("resolvconf failed with status %d", err); + g_clear_error (error); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "resolvconf failed with status %d", err); + return SR_ERROR; + } - return retval ? SR_SUCCESS : SR_ERROR; + return success ? SR_SUCCESS : SR_ERROR; } #define MY_RESOLV_CONF NMRUNDIR "/resolv.conf" @@ -536,7 +543,7 @@ update_resolv_conf (NMDnsManager *self, { FILE *f; struct stat st; - gboolean ret; + gboolean success; /* If we are not managing /etc/resolv.conf and it points to * MY_RESOLV_CONF, don't write the private DNS configuration to @@ -544,15 +551,12 @@ update_resolv_conf (NMDnsManager *self, * some external application. */ if (!install_etc) { - char *path = g_file_read_link (_PATH_RESCONF, NULL); - gboolean ours = !g_strcmp0 (path, MY_RESOLV_CONF); + gs_free char *path = g_file_read_link (_PATH_RESCONF, NULL); - g_free (path); - - if (ours) { + if (g_strcmp0 (path, MY_RESOLV_CONF) == 0) { _LOGD ("not updating " MY_RESOLV_CONF " since it points to " _PATH_RESCONF); - return SR_ERROR; + return SR_SUCCESS; } } @@ -560,36 +564,35 @@ update_resolv_conf (NMDnsManager *self, g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not open %s: %s\n", + "Could not open %s: %s", MY_RESOLV_CONF_TMP, g_strerror (errno)); return SR_ERROR; } - ret = write_resolv_conf (f, searches, nameservers, options, error); + success = write_resolv_conf (f, searches, nameservers, options, error); if (fclose (f) < 0) { - if (ret) { + if (success) { /* only set an error here if write_resolv_conf() was successful, * since its error is more important. */ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not close %s: %s\n", + "Could not close %s: %s", MY_RESOLV_CONF_TMP, g_strerror (errno)); } - } - - if (!ret) + return SR_ERROR; + } else if (!success) return SR_ERROR; if (rename (MY_RESOLV_CONF_TMP, MY_RESOLV_CONF) < 0) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not replace %s: %s\n", + "Could not replace %s: %s", MY_RESOLV_CONF, g_strerror (errno)); return SR_ERROR; @@ -598,44 +601,50 @@ update_resolv_conf (NMDnsManager *self, if (!install_etc) return SR_SUCCESS; - /* Don't overwrite a symbolic link unless it points to MY_RESOLV_CONF. */ + /* A symlink pointing to NM's own resolv.conf (MY_RESOLV_CONF) is always + * overwritten to ensure that changes are indicated with inotify. Symlinks + * pointing to any other file are never overwritten. + */ if (lstat (_PATH_RESCONF, &st) != -1) { - /* Don't overwrite a symbolic link. */ if (S_ISLNK (st.st_mode)) { if (stat (_PATH_RESCONF, &st) != -1) { - char *path = g_file_read_link (_PATH_RESCONF, NULL); - gboolean not_ours = g_strcmp0 (path, MY_RESOLV_CONF) != 0; + gs_free char *path = g_file_read_link (_PATH_RESCONF, NULL); - g_free (path); - if (not_ours) + if (g_strcmp0 (path, MY_RESOLV_CONF) != 0) { + /* It's not NM's symlink; do nothing */ return SR_SUCCESS; + } + + /* resolv.conf is a symlink owned by NM and the target is accessible + */ } else { - if (errno != ENOENT) - return SR_SUCCESS; - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not stat %s: %s\n", - _PATH_RESCONF, - g_strerror (errno)); - return SR_ERROR; + /* resolv.conf is a symlink but the target is not accessible; + * some other program is probably managing resolv.conf and + * NM should not touch it. + */ + return SR_SUCCESS; } } } else if (errno != ENOENT) { + /* NM cannot read /etc/resolv.conf */ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not lstat %s: %s\n", + "Could not lstat %s: %s", _PATH_RESCONF, g_strerror (errno)); return SR_ERROR; } + /* By this point, either /etc/resolv.conf does not exist, is a regular + * file, or is a symlink already owned by NM. In all cases /etc/resolv.conf + * is replaced with a symlink pointing to NM's resolv.conf in /var/run/. + */ if (unlink (RESOLV_CONF_TMP) == -1 && errno != ENOENT) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not unlink %s: %s\n", + "Could not unlink %s: %s", RESOLV_CONF_TMP, g_strerror (errno)); return SR_ERROR; @@ -645,7 +654,7 @@ update_resolv_conf (NMDnsManager *self, g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not create symlink %s pointing to %s: %s\n", + "Could not create symlink %s pointing to %s: %s", RESOLV_CONF_TMP, MY_RESOLV_CONF, g_strerror (errno)); @@ -656,7 +665,7 @@ update_resolv_conf (NMDnsManager *self, g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Could not rename %s to %s: %s\n", + "Could not rename %s to %s: %s", RESOLV_CONF_TMP, _PATH_RESCONF, g_strerror (errno)); @@ -799,6 +808,7 @@ update_dns (NMDnsManager *self, g_return_val_if_fail (!error || !*error, FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); + nm_clear_g_source (&priv->plugin_ratelimit.timer); if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) { update = FALSE; @@ -863,7 +873,8 @@ update_dns (NMDnsManager *self, if (priv->hostname) { const char *hostdomain = strchr (priv->hostname, '.'); - if (hostdomain) { + if ( hostdomain + && !nm_utils_ipaddr_valid (AF_UNSPEC, priv->hostname)) { hostdomain++; if (DOMAIN_IS_VALID (hostdomain)) add_string_item (rc.searches, hostdomain); @@ -1022,20 +1033,47 @@ plugin_failed (NMDnsPlugin *plugin, gpointer user_data) } } -static void -plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) +static gboolean +plugin_child_quit_update_dns (gpointer user_data) { - NMDnsManager *self = NM_DNS_MANAGER (user_data); GError *error = NULL; - - _LOGW ("plugin %s child quit unexpectedly; refreshing DNS", - nm_dns_plugin_get_name (plugin)); + NMDnsManager *self = NM_DNS_MANAGER (user_data); /* Let the plugin try to spawn the child again */ if (!update_dns (self, FALSE, &error)) { _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } + + return G_SOURCE_REMOVE; +} + +static void +plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) +{ + NMDnsManager *self = NM_DNS_MANAGER (user_data); + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + gint64 ts = nm_utils_get_monotonic_timestamp_ms (); + + _LOGW ("plugin %s child quit unexpectedly", nm_dns_plugin_get_name (plugin)); + + if ( !priv->plugin_ratelimit.ts + || (ts - priv->plugin_ratelimit.ts) / 1000 > PLUGIN_RATELIMIT_INTERVAL) { + priv->plugin_ratelimit.ts = ts; + priv->plugin_ratelimit.num_restarts = 0; + } else { + priv->plugin_ratelimit.num_restarts++; + if (priv->plugin_ratelimit.num_restarts > PLUGIN_RATELIMIT_BURST) { + _LOGW ("plugin %s child respawning too fast, delaying update for %u seconds", + nm_dns_plugin_get_name (plugin), PLUGIN_RATELIMIT_DELAY); + priv->plugin_ratelimit.timer = g_timeout_add_seconds (PLUGIN_RATELIMIT_DELAY, + plugin_child_quit_update_dns, + self); + return; + } + } + + plugin_child_quit_update_dns (self); } gboolean diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index a8236696..8313ed13 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -17,7 +17,7 @@ * */ -#include "config.h" +#include "nm-default.h" #include <string.h> #include <stdlib.h> @@ -25,7 +25,6 @@ #include <sys/types.h> #include <sys/wait.h> -#include "nm-default.h" #include "nm-dns-plugin.h" #include "NetworkManagerUtils.h" @@ -33,7 +32,7 @@ typedef struct { gboolean disposed; GPid pid; - guint32 watch_id; + guint watch_id; char *progname; char *pidfile; } NMDnsPluginPrivate; @@ -130,6 +129,7 @@ watch_cb (GPid pid, gint status, gpointer user_data) NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); priv->pid = 0; + priv->watch_id = 0; g_free (priv->progname); priv->progname = NULL; diff --git a/src/dns-manager/nm-dns-unbound.c b/src/dns-manager/nm-dns-unbound.c index d36e3f85..4c1af103 100644 --- a/src/dns-manager/nm-dns-unbound.c +++ b/src/dns-manager/nm-dns-unbound.c @@ -17,7 +17,7 @@ * Copyright (C) 2014 Red Hat, Inc. * Author: Pavel Šimerda <psimerda@redhat.com> */ -#include "config.h" +#include "nm-default.h" #include "nm-dns-unbound.h" #include "NetworkManagerUtils.h" diff --git a/src/dns-manager/nm-dns-utils.c b/src/dns-manager/nm-dns-utils.c index 4a5255a4..e920611a 100644 --- a/src/dns-manager/nm-dns-utils.c +++ b/src/dns-manager/nm-dns-utils.c @@ -17,7 +17,7 @@ * */ -#include "config.h" +#include "nm-default.h" #include <arpa/inet.h> #include <string.h> |