From 853b8152663111bba8142b05752aa9eb560a340c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 21 Apr 2016 09:38:26 +0200 Subject: [PATCH 1/7] dns: minor code cleanup in NMDnsPlugin (cherry picked from commit de9ad6bd8cd032a370f7795334ee8dd77a5fcd8d) --- src/dns-manager/nm-dns-plugin.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index 47322d2ae2..850bd9a3e3 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -96,8 +96,7 @@ _clear_pidfile (NMDnsPlugin *self) if (priv->pidfile) { unlink (priv->pidfile); - g_free (priv->pidfile); - priv->pidfile = NULL; + g_clear_pointer (&priv->pidfile, g_free); } } @@ -154,8 +153,8 @@ watch_cb (GPid pid, gint status, gpointer user_data) priv->pid = 0; priv->watch_id = 0; - g_free (priv->progname); - priv->progname = NULL; + + g_clear_pointer (&priv->progname, g_free); _clear_pidfile (self); @@ -172,8 +171,7 @@ nm_dns_plugin_child_spawn (NMDnsPlugin *self, GError *error = NULL; char *cmdline; - g_return_val_if_fail (argv != NULL, 0); - g_return_val_if_fail (argv[0] != NULL, 0); + g_return_val_if_fail (argv && argv[0], 0); g_warn_if_fail (priv->progname == NULL); g_free (priv->progname); @@ -217,8 +215,7 @@ nm_dns_plugin_child_kill (NMDnsPlugin *self) if (priv->pid) { nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, priv->progname, NULL, 1000, 0); priv->pid = 0; - g_free (priv->progname); - priv->progname = NULL; + g_clear_pointer (&priv->progname, g_free); } _clear_pidfile (self); From 3571356d9da55a9e68ac4dc2edf85d5b6d07f04f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 21 Apr 2016 09:39:25 +0200 Subject: [PATCH 2/7] dns: remove unnecessary finalize() implementation from NMDnsPlugin dispose() already calls nm_dns_plugin_child_kill(), which clears both pidfile and progname. (cherry picked from commit 252258eb2a57af0dfa071d41d7e483d431f824fb) --- src/dns-manager/nm-dns-plugin.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index 850bd9a3e3..c510e65b13 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -240,18 +240,6 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_dns_plugin_parent_class)->dispose (object); } -static void -finalize (GObject *object) -{ - NMDnsPlugin *self = NM_DNS_PLUGIN (object); - NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); - - g_free (priv->progname); - g_free (priv->pidfile); - - G_OBJECT_CLASS (nm_dns_plugin_parent_class)->finalize (object); -} - static void nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class) { @@ -261,7 +249,6 @@ nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class) /* virtual methods */ object_class->dispose = dispose; - object_class->finalize = finalize; plugin_class->is_caching = is_caching; /* signals */ From 4fa0f205b69d8835e901c280031a854fdc72c234 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 21 Apr 2016 09:48:44 +0200 Subject: [PATCH 3/7] dns: cleanup managing child process for NMDnsPlugin The 4 private fields pid, watch_id, progname and pidfile strictly belong together. When spawning a child, we set all 4 of them and when killing the child all get cleared. Cleanup to code to always set those 4 fields together. (cherry picked from commit 4d5ca7f9de90d139ea2760f05c13f4326ef8e209) --- src/dns-manager/nm-dns-plugin.c | 54 +++++++++++++++++---------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index c510e65b13..16b2979c14 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -153,9 +153,7 @@ watch_cb (GPid pid, gint status, gpointer user_data) priv->pid = 0; priv->watch_id = 0; - g_clear_pointer (&priv->progname, g_free); - _clear_pidfile (self); g_signal_emit (self, signals[CHILD_QUIT], 0, status); @@ -167,42 +165,47 @@ nm_dns_plugin_child_spawn (NMDnsPlugin *self, const char *pidfile, const char *kill_match) { - NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); + NMDnsPluginPrivate *priv; GError *error = NULL; - char *cmdline; + GPid pid; + gs_free char *cmdline = NULL; + gs_free char *progname = NULL; g_return_val_if_fail (argv && argv[0], 0); + g_return_val_if_fail (NM_IS_DNS_PLUGIN (self), 0); - g_warn_if_fail (priv->progname == NULL); - g_free (priv->progname); - priv->progname = g_path_get_basename (argv[0]); + priv = NM_DNS_PLUGIN_GET_PRIVATE (self); - kill_existing (priv->progname, pidfile, kill_match); + g_return_val_if_fail (!priv->pid, 0); + nm_assert (!priv->progname); + nm_assert (!priv->watch_id); + nm_assert (!priv->pidfile); - g_warn_if_fail (priv->pidfile == NULL); - g_clear_pointer (&priv->pidfile, g_free); - priv->pidfile = g_strdup (pidfile); + progname = g_path_get_basename (argv[0]); + kill_existing (progname, pidfile, kill_match); - nm_log_info (LOGD_DNS, "DNS: starting %s...", priv->progname); - cmdline = g_strjoinv (" ", (char **) argv); - nm_log_dbg (LOGD_DNS, "DNS: command line: %s", cmdline); - g_free (cmdline); + nm_log_info (LOGD_DNS, "DNS: starting %s...", progname); + nm_log_dbg (LOGD_DNS, "DNS: command line: %s", + (cmdline = g_strjoinv (" ", (char **) argv))); - priv->pid = 0; - if (g_spawn_async (NULL, (char **) argv, NULL, + if (!g_spawn_async (NULL, (char **) argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, nm_utils_setpgid, NULL, - &priv->pid, + &pid, &error)) { - nm_log_dbg (LOGD_DNS, "%s started with pid %d", priv->progname, priv->pid); - priv->watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) watch_cb, self); - } else { nm_log_warn (LOGD_DNS, "Failed to spawn %s: %s", - priv->progname, error->message); + progname, error->message); g_clear_error (&error); + return 0; } - return priv->pid; + nm_log_dbg (LOGD_DNS, "%s started with pid %d", progname, pid); + priv->watch_id = g_child_watch_add (pid, (GChildWatchFunc) watch_cb, self); + priv->pid = pid; + priv->progname = nm_unauto (&progname); + priv->pidfile = g_strdup (pidfile); + + return pid; } gboolean @@ -211,13 +214,12 @@ nm_dns_plugin_child_kill (NMDnsPlugin *self) NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); nm_clear_g_source (&priv->watch_id); - if (priv->pid) { - nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, priv->progname, NULL, 1000, 0); + nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, + priv->progname ?: "", NULL, 1000, 0); priv->pid = 0; g_clear_pointer (&priv->progname, g_free); } - _clear_pidfile (self); return TRUE; From 9f3c8f3e01a11199eea08e935229010bac9b16ca Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 21 Apr 2016 09:57:11 +0200 Subject: [PATCH 4/7] dns: add and use _NMLOG() logging macro in nm-dns-plugin.c (cherry picked from commit 44a61eda7723d3b4573863be84798d8b261f9aea) --- src/dns-manager/nm-dns-plugin.c | 40 +++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index 16b2979c14..d5cb882246 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -48,7 +48,29 @@ enum { }; static guint signals[LAST_SIGNAL] = { 0 }; -/********************************************/ +/******************************************************************************/ + +#define _NMLOG_PREFIX_NAME "dns-plugin" +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG(level, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ + char __prefix[20]; \ + const NMDnsPlugin *const __self = (self); \ + \ + _nm_log (__level, _NMLOG_DOMAIN, 0, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (!__self \ + ? "" \ + : nm_sprintf_buf (__prefix, "[%p]", __self)) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/******************************************************************************/ gboolean nm_dns_plugin_update (NMDnsPlugin *self, @@ -137,7 +159,7 @@ kill_existing (const char *progname, const char *pidfile, const char *kill_match if (!strstr (cmdline_contents, kill_match)) goto out; - nm_utils_kill_process_sync (pid, start_time, SIGKILL, LOGD_DNS, + nm_utils_kill_process_sync (pid, start_time, SIGKILL, _NMLOG_DOMAIN, progname ?: "", 0, 0, 1000); @@ -184,22 +206,22 @@ nm_dns_plugin_child_spawn (NMDnsPlugin *self, progname = g_path_get_basename (argv[0]); kill_existing (progname, pidfile, kill_match); - nm_log_info (LOGD_DNS, "DNS: starting %s...", progname); - nm_log_dbg (LOGD_DNS, "DNS: command line: %s", - (cmdline = g_strjoinv (" ", (char **) argv))); + _LOGI ("starting %s...", progname); + _LOGD ("command line: %s", + (cmdline = g_strjoinv (" ", (char **) argv))); if (!g_spawn_async (NULL, (char **) argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, nm_utils_setpgid, NULL, &pid, &error)) { - nm_log_warn (LOGD_DNS, "Failed to spawn %s: %s", - progname, error->message); + _LOGW ("failed to spawn %s: %s", + progname, error->message); g_clear_error (&error); return 0; } - nm_log_dbg (LOGD_DNS, "%s started with pid %d", progname, pid); + _LOGD ("%s started with pid %d", progname, pid); priv->watch_id = g_child_watch_add (pid, (GChildWatchFunc) watch_cb, self); priv->pid = pid; priv->progname = nm_unauto (&progname); @@ -215,7 +237,7 @@ nm_dns_plugin_child_kill (NMDnsPlugin *self) nm_clear_g_source (&priv->watch_id); if (priv->pid) { - nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, + nm_utils_kill_child_sync (priv->pid, SIGTERM, _NMLOG_DOMAIN, priv->progname ?: "", NULL, 1000, 0); priv->pid = 0; g_clear_pointer (&priv->progname, g_free); From 08673a623f1949bd2fdb6f65d90bce794ccb72de Mon Sep 17 00:00:00 2001 From: Mathieu Trudel-Lapierre Date: Tue, 22 Mar 2016 10:03:44 -0400 Subject: [PATCH 5/7] dns: use DBus to make dnsmasq nameserver changes Use DBus to make nameserver updates rather than restarting the dnsmasq binary again and again. Signed-off-by: Mathieu Trudel-Lapierre https://mail.gnome.org/archives/networkmanager-list/2016-March/msg00144.html (cherry picked from commit 18282df0aaa3b55576df762f222f1a602d31bbd7) --- src/dns-manager/nm-dns-dnsmasq.c | 340 +++++++++++++++++++----- src/dns-manager/nm-dns-manager.c | 22 ++ src/dns-manager/nm-dns-plugin.c | 10 + src/dns-manager/nm-dns-plugin.h | 1 + src/org.freedesktop.NetworkManager.conf | 10 + 5 files changed, 319 insertions(+), 64 deletions(-) diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c index 5ead5ecf3b..863d81fccd 100644 --- a/src/dns-manager/nm-dns-dnsmasq.c +++ b/src/dns-manager/nm-dns-dnsmasq.c @@ -32,6 +32,7 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "nm-dns-utils.h" +#include "nm-bus-manager.h" #include "NetworkManagerUtils.h" G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) @@ -42,8 +43,16 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) #define CONFFILE NMRUNDIR "/dnsmasq.conf" #define CONFDIR NMCONFDIR "/dnsmasq.d" +#define DNSMASQ_DBUS_SERVICE "org.freedesktop.NetworkManager.dnsmasq" +#define DNSMASQ_DBUS_PATH "/uk/org/thekelleys/dnsmasq" + typedef struct { - guint32 foo; + NMBusManager *dbus_mgr; + GDBusConnection *connection; + GDBusProxy *dnsmasq; + gboolean running; + + GVariantBuilder *servers; } NMDnsDnsmasqPrivate; /*****************************************************************************/ @@ -61,8 +70,27 @@ typedef struct { /*****************************************************************************/ +static void +add_dnsmasq_nameserver (GVariantBuilder *servers, + const char *ip, + const char *domain) +{ + nm_log_dbg (LOGD_DNS, "Adding nameserver '%s' for domain '%s'", + ip, domain); + + g_return_if_fail (ip); + + g_variant_builder_open (servers, G_VARIANT_TYPE ("as")); + + if (domain) + g_variant_builder_add (servers, "s", domain); + g_variant_builder_add (servers, "s", ip); + + g_variant_builder_close (servers); +} + static gboolean -add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split) +add_ip4_config (GVariantBuilder *servers, NMIP4Config *ip4, gboolean split) { char buf[INET_ADDRSTRLEN]; in_addr_t addr; @@ -84,9 +112,9 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split) /* searches are preferred over domains */ n = nm_ip4_config_get_num_searches (ip4); for (i = 0; i < n; i++) { - g_string_append_printf (str, "server=/%s/%s\n", - nm_ip4_config_get_search (ip4, i), - buf); + add_dnsmasq_nameserver (servers, + buf, + nm_ip4_config_get_search (ip4, i)); added = TRUE; } @@ -94,9 +122,9 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split) /* If not searches, use any domains */ n = nm_ip4_config_get_num_domains (ip4); for (i = 0; i < n; i++) { - g_string_append_printf (str, "server=/%s/%s\n", - nm_ip4_config_get_domain (ip4, i), - buf); + add_dnsmasq_nameserver (servers, + buf, + nm_ip4_config_get_domain (ip4, i)); added = TRUE; } } @@ -107,7 +135,7 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split) domains = nm_dns_utils_get_ip4_rdns_domains (ip4); if (domains) { for (iter = domains; iter && *iter; iter++) - g_string_append_printf (str, "server=/%s/%s\n", *iter, buf); + add_dnsmasq_nameserver (servers, buf, *iter); g_strfreev (domains); added = TRUE; } @@ -118,7 +146,8 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split) if (!added) { for (i = 0; i < nnameservers; i++) { addr = nm_ip4_config_get_nameserver (ip4, i); - g_string_append_printf (str, "server=%s\n", nm_utils_inet4_ntop (addr, NULL)); + add_dnsmasq_nameserver (servers, + nm_utils_inet4_ntop (addr, NULL), NULL); } } @@ -148,7 +177,7 @@ ip6_addr_to_string (const struct in6_addr *addr, const char *iface) } static void -add_global_config (GString *str, const NMGlobalDnsConfig *config) +add_global_config (GVariantBuilder *dnsmasq_servers, const NMGlobalDnsConfig *config) { guint i, j; @@ -163,16 +192,16 @@ add_global_config (GString *str, const NMGlobalDnsConfig *config) for (j = 0; servers && servers[j]; j++) { if (!strcmp (name, "*")) - g_string_append_printf (str, "server=%s\n", servers[j]); + add_dnsmasq_nameserver (dnsmasq_servers, servers[j], NULL); else - g_string_append_printf (str, "server=/%s/%s\n", name, servers[j]); + add_dnsmasq_nameserver (dnsmasq_servers, servers[j], name); } } } static gboolean -add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) +add_ip6_config (GVariantBuilder *servers, NMIP6Config *ip6, gboolean split) { const struct in6_addr *addr; char *buf = NULL; @@ -196,9 +225,9 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) /* searches are preferred over domains */ n = nm_ip6_config_get_num_searches (ip6); for (i = 0; i < n; i++) { - g_string_append_printf (str, "server=/%s/%s\n", - nm_ip6_config_get_search (ip6, i), - buf); + add_dnsmasq_nameserver (servers, + buf, + nm_ip6_config_get_search (ip6, i)); added = TRUE; } @@ -206,9 +235,9 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) /* If not searches, use any domains */ n = nm_ip6_config_get_num_domains (ip6); for (i = 0; i < n; i++) { - g_string_append_printf (str, "server=/%s/%s\n", - nm_ip6_config_get_domain (ip6, i), - buf); + add_dnsmasq_nameserver (servers, + buf, + nm_ip6_config_get_domain (ip6, i)); added = TRUE; } } @@ -223,7 +252,7 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) addr = nm_ip6_config_get_nameserver (ip6, i); buf = ip6_addr_to_string (addr, iface); if (buf) { - g_string_append_printf (str, "server=%s\n", buf); + add_dnsmasq_nameserver (servers, buf, NULL); g_free (buf); } } @@ -232,30 +261,155 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) return TRUE; } -static gboolean -update (NMDnsPlugin *plugin, - const GSList *vpn_configs, - const GSList *dev_configs, - const GSList *other_configs, - const NMGlobalDnsConfig *global_config, - const char *hostname) +static void +dnsmasq_update_done (GObject *source, GAsyncResult *res, gpointer user_data) { - NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); + NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data); + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); + GError *error = NULL; + GVariant *response; + + response = g_dbus_proxy_call_finish (priv->dnsmasq, res, &error); + if (error) { + nm_log_warn (LOGD_DNS, "Dnsmasq update failed: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } + + if (response) + g_variant_unref (response); +} + +static gboolean +send_dnsmasq_update (NMDnsDnsmasq *self) +{ + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); + + nm_log_dbg (LOGD_DNS, "trying to update dnsmasq nameservers"); + + if (!priv->servers) { + nm_log_warn (LOGD_DNS, "no nameservers list to send update"); + return FALSE; + } + + if (priv->running) { + g_dbus_proxy_call (priv->dnsmasq, + "SetServersEx", + g_variant_new ("(aas)", + priv->servers), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) dnsmasq_update_done, + self); + g_variant_builder_unref (priv->servers); + priv->servers = NULL; + } else { + nm_log_warn (LOGD_DNS, "Dnsmasq not found on the bus."); + nm_log_warn (LOGD_DNS, "The nameserver update will be sent when dnsmasq appears."); + } + + return TRUE; +} + +static void +name_owner_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data); + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); + gs_free char *owner = NULL; + + owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); + if (owner) { + nm_log_info (LOGD_DNS, "dnsmasq appeared as %s", owner); + priv->running = TRUE; + g_signal_emit_by_name (self, NM_DNS_PLUGIN_APPEARED); + } else { + nm_log_info (LOGD_DNS, "dnsmasq disappeared"); + priv->running = FALSE; + g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); + } +} + +static void +dnsmasq_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data); + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); + GError *error = NULL; + gs_free char *owner = NULL; + + nm_log_dbg (LOGD_DNS, "dnsmasq proxy creation returned"); + + if (priv->dnsmasq) { + nm_log_dbg (LOGD_DNS, "already have an old proxy; replacing."); + g_object_unref (priv->dnsmasq); + priv->dnsmasq = NULL; + } + + priv->dnsmasq = g_dbus_proxy_new_finish (res, &error); + if (!priv->dnsmasq) { + nm_log_warn (LOGD_DNS, "Failed to connect to dnsmasq via DBus: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } else { + nm_log_dbg (LOGD_DNS, "dnsmasq proxy creation successful"); + + g_signal_connect (priv->dnsmasq, "notify::g-name-owner", + G_CALLBACK (name_owner_changed), self); + owner = g_dbus_proxy_get_name_owner (priv->dnsmasq); + priv->running = (owner != NULL); + + if (priv->running && priv->servers) + send_dnsmasq_update (self); + } +} + +static void +get_dnsmasq_proxy (NMDnsDnsmasq *self) +{ + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); + + g_return_if_fail (!priv->dnsmasq); + + nm_log_dbg (LOGD_DNS, "retrieving dnsmasq proxy"); + + if (!priv->dnsmasq) { + g_dbus_proxy_new (priv->connection, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + DNSMASQ_DBUS_SERVICE, + DNSMASQ_DBUS_PATH, + DNSMASQ_DBUS_SERVICE, + NULL, + dnsmasq_proxy_cb, + self); + } +} + +static gboolean +start_dnsmasq (NMDnsDnsmasq *self) +{ + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); const char *dm_binary; - GString *conf; - GSList *iter; const char *argv[15]; GError *error = NULL; int ignored; GPid pid = 0; guint idx = 0; + GString *conf; - /* Kill the old dnsmasq; there doesn't appear to be a way to get dnsmasq - * to reread the config file using SIGHUP or similar. This is a small race - * here when restarting dnsmasq when DNS requests could go to the upstream - * servers instead of to dnsmasq. + /* dnsmasq is probably already started; if it's the case, don't do + * anything more. */ - nm_dns_plugin_child_kill (plugin); + if (priv->running) { + nm_log_dbg (LOGD_DNS, "dnsmasq is already running"); + return TRUE; + } + + /* Start dnsmasq */ dm_binary = nm_utils_find_helper ("dnsmasq", DNSMASQ_PATH, NULL); if (!dm_binary) { @@ -266,34 +420,6 @@ update (NMDnsPlugin *plugin, /* Build up the new dnsmasq config file */ conf = g_string_sized_new (150); - if (global_config) - add_global_config (conf, global_config); - else { - /* Use split DNS for VPN configs */ - for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) { - if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE); - else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE); - } - - /* Now add interface configs without split DNS */ - for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) { - if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); - else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); - } - - /* And any other random configs */ - for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) { - if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); - else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); - } - } - /* Write out the config file */ if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) { _LOGW ("failed to write dnsmasq config file %s: %s", @@ -317,6 +443,7 @@ update (NMDnsPlugin *plugin, argv[idx++] = "--conf-file=" CONFFILE; argv[idx++] = "--cache-size=400"; argv[idx++] = "--proxy-dnssec"; /* Allow DNSSEC to pass through */ + argv[idx++] = "--enable-dbus=" DNSMASQ_DBUS_SERVICE; /* dnsmasq exits if the conf dir is not present */ if (g_file_test (CONFDIR, G_FILE_TEST_IS_DIR)) @@ -328,11 +455,77 @@ update (NMDnsPlugin *plugin, /* And finally spawn dnsmasq */ pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq"); + if (pid && !priv->dnsmasq) + get_dnsmasq_proxy (self); out: g_string_free (conf, TRUE); return pid ? TRUE : FALSE; } +static gboolean +update (NMDnsPlugin *plugin, + const GSList *vpn_configs, + const GSList *dev_configs, + const GSList *other_configs, + const NMGlobalDnsConfig *global_config, + const char *hostname) +{ + NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); + GSList *iter; + GError *error = NULL; + gboolean ret = FALSE; + + if (!priv->running) + start_dnsmasq (self); + + if (priv->servers) + g_variant_builder_unref (priv->servers); + priv->servers = g_variant_builder_new (G_VARIANT_TYPE ("aas")); + + if (global_config) + add_global_config (priv->servers, global_config); + else { + /* Use split DNS for VPN configs */ + for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) { + if (NM_IS_IP4_CONFIG (iter->data)) + add_ip4_config (priv->servers, NM_IP4_CONFIG (iter->data), TRUE); + else if (NM_IS_IP6_CONFIG (iter->data)) + add_ip6_config (priv->servers, NM_IP6_CONFIG (iter->data), TRUE); + } + + /* Now add interface configs without split DNS */ + for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) { + if (NM_IS_IP4_CONFIG (iter->data)) + add_ip4_config (priv->servers, NM_IP4_CONFIG (iter->data), FALSE); + else if (NM_IS_IP6_CONFIG (iter->data)) + add_ip6_config (priv->servers, NM_IP6_CONFIG (iter->data), FALSE); + } + + /* And any other random configs */ + for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) { + if (NM_IS_IP4_CONFIG (iter->data)) + add_ip4_config (priv->servers, NM_IP4_CONFIG (iter->data), FALSE); + else if (NM_IS_IP6_CONFIG (iter->data)) + add_ip6_config (priv->servers, NM_IP6_CONFIG (iter->data), FALSE); + } + } + + ret = send_dnsmasq_update (self); + + /* If all the configs lists are empty, there is just nothing to be caching -- + * we cleared up the dnsmasq cache; but we should also fail the update, so + * that we don't write 127.0.0.1 to resolv.conf. + */ + if (((vpn_configs && g_slist_length ((GSList *) vpn_configs) < 1) || !vpn_configs) && + ((dev_configs && g_slist_length ((GSList *) dev_configs) < 1) || !dev_configs) && + ((other_configs && g_slist_length ((GSList *) other_configs) < 1) || !other_configs)) + ret = FALSE; + +out: + return ret; +} + /****************************************************************/ static const char * @@ -405,13 +598,32 @@ nm_dns_dnsmasq_new (void) static void nm_dns_dnsmasq_init (NMDnsDnsmasq *self) { + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); + + priv->dbus_mgr = nm_bus_manager_get (); + priv->running = FALSE; + + g_assert (priv->dbus_mgr); + + priv->connection = nm_bus_manager_get_connection (priv->dbus_mgr); + if (!priv->connection) + nm_log_warn (LOGD_DNS, "Could not get the system bus to speak to dnsmasq."); + else + get_dnsmasq_proxy (self); } static void dispose (GObject *object) { + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (object); + unlink (CONFFILE); + if (priv->dbus_mgr) { + g_object_unref (priv->dbus_mgr); + priv->dbus_mgr = NULL; + } + G_OBJECT_CLASS (nm_dns_dnsmasq_parent_class)->dispose (object); } diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index b42af167cd..f65e8d11d1 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -1064,6 +1064,27 @@ update_dns (NMDnsManager *self, return !update || result == SR_SUCCESS; } +static void +plugin_appeared (NMDnsPlugin *plugin, gpointer user_data) +{ + NMDnsManager *self = NM_DNS_MANAGER (user_data); + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + GError *error = NULL; + + /* Not applicable to non-caching plugins */ + if (!nm_dns_plugin_is_caching (plugin)) + return; + + /* Try to update DNS again; since it's now available on the bus this + * might work. */ + if (!update_dns (self, FALSE, &error)) { + nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } +} + static void plugin_failed (NMDnsPlugin *plugin, gpointer user_data) { @@ -1432,6 +1453,7 @@ init_resolv_conf_mode (NMDnsManager *self) g_signal_connect (priv->plugin, NM_DNS_PLUGIN_FAILED, G_CALLBACK (plugin_failed), self); g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self); + g_signal_connect (priv->plugin, NM_DNS_PLUGIN_APPEARED, G_CALLBACK (plugin_appeared), self); _NMLOG (immutable ? LOGL_WARN : LOGL_INFO, "%s%s%s%s%s%s", diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index d5cb882246..76c7c3e63c 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -43,6 +43,7 @@ G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_A enum { FAILED, + APPEARED, CHILD_QUIT, LAST_SIGNAL }; @@ -285,6 +286,15 @@ nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + signals[APPEARED] = + g_signal_new (NM_DNS_PLUGIN_APPEARED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDnsPluginClass, failed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[CHILD_QUIT] = g_signal_new (NM_DNS_PLUGIN_CHILD_QUIT, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h index 7ecaa424dc..6ed5b1bcc0 100644 --- a/src/dns-manager/nm-dns-plugin.h +++ b/src/dns-manager/nm-dns-plugin.h @@ -31,6 +31,7 @@ #define NM_DNS_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass)) #define NM_DNS_PLUGIN_FAILED "failed" +#define NM_DNS_PLUGIN_APPEARED "appeared" #define NM_DNS_PLUGIN_CHILD_QUIT "child-quit" #define IP_CONFIG_IFACE_TAG "dns-manager-iface" diff --git a/src/org.freedesktop.NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf index dd630e1986..d130f7e271 100644 --- a/src/org.freedesktop.NetworkManager.conf +++ b/src/org.freedesktop.NetworkManager.conf @@ -26,6 +26,13 @@ + + + + @@ -127,6 +134,9 @@ + + + 1024 From 99168f6009ace68c57c3af30944b0d95d01793c2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 14 Apr 2016 13:14:14 +0200 Subject: [PATCH 6/7] dns: various cleanup for new dnsmasq's D-Bus support (cherry picked from commit baaec81aea9cd338b7bac66fb74f22e8e1b18301) --- src/dns-manager/nm-dns-dnsmasq.c | 293 ++++++++++++------------------- src/dns-manager/nm-dns-manager.c | 22 --- src/dns-manager/nm-dns-plugin.c | 10 -- src/dns-manager/nm-dns-plugin.h | 1 - 4 files changed, 116 insertions(+), 210 deletions(-) diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c index 863d81fccd..77ac548d8c 100644 --- a/src/dns-manager/nm-dns-dnsmasq.c +++ b/src/dns-manager/nm-dns-dnsmasq.c @@ -40,19 +40,17 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) #define NM_DNS_DNSMASQ_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasqPrivate)) #define PIDFILE NMRUNDIR "/dnsmasq.pid" -#define CONFFILE NMRUNDIR "/dnsmasq.conf" #define CONFDIR NMCONFDIR "/dnsmasq.d" #define DNSMASQ_DBUS_SERVICE "org.freedesktop.NetworkManager.dnsmasq" #define DNSMASQ_DBUS_PATH "/uk/org/thekelleys/dnsmasq" typedef struct { - NMBusManager *dbus_mgr; - GDBusConnection *connection; GDBusProxy *dnsmasq; + GCancellable *dnsmasq_cancellable; gboolean running; - GVariantBuilder *servers; + GVariant *set_server_ex_args; } NMDnsDnsmasqPrivate; /*****************************************************************************/ @@ -71,26 +69,27 @@ typedef struct { /*****************************************************************************/ static void -add_dnsmasq_nameserver (GVariantBuilder *servers, +add_dnsmasq_nameserver (NMDnsDnsmasq *self, + GVariantBuilder *servers, const char *ip, const char *domain) { - nm_log_dbg (LOGD_DNS, "Adding nameserver '%s' for domain '%s'", - ip, domain); - g_return_if_fail (ip); + _LOGD ("adding nameserver '%s'%s%s%s", ip, + NM_PRINT_FMT_QUOTED (domain, " for domain \"", domain, "\"", "")); + g_variant_builder_open (servers, G_VARIANT_TYPE ("as")); + g_variant_builder_add (servers, "s", ip); if (domain) g_variant_builder_add (servers, "s", domain); - g_variant_builder_add (servers, "s", ip); g_variant_builder_close (servers); } static gboolean -add_ip4_config (GVariantBuilder *servers, NMIP4Config *ip4, gboolean split) +add_ip4_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP4Config *ip4, gboolean split) { char buf[INET_ADDRSTRLEN]; in_addr_t addr; @@ -112,7 +111,8 @@ add_ip4_config (GVariantBuilder *servers, NMIP4Config *ip4, gboolean split) /* searches are preferred over domains */ n = nm_ip4_config_get_num_searches (ip4); for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (servers, + add_dnsmasq_nameserver (self, + servers, buf, nm_ip4_config_get_search (ip4, i)); added = TRUE; @@ -122,7 +122,8 @@ add_ip4_config (GVariantBuilder *servers, NMIP4Config *ip4, gboolean split) /* If not searches, use any domains */ n = nm_ip4_config_get_num_domains (ip4); for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (servers, + add_dnsmasq_nameserver (self, + servers, buf, nm_ip4_config_get_domain (ip4, i)); added = TRUE; @@ -135,7 +136,7 @@ add_ip4_config (GVariantBuilder *servers, NMIP4Config *ip4, gboolean split) domains = nm_dns_utils_get_ip4_rdns_domains (ip4); if (domains) { for (iter = domains; iter && *iter; iter++) - add_dnsmasq_nameserver (servers, buf, *iter); + add_dnsmasq_nameserver (self, servers, buf, *iter); g_strfreev (domains); added = TRUE; } @@ -146,7 +147,7 @@ add_ip4_config (GVariantBuilder *servers, NMIP4Config *ip4, gboolean split) if (!added) { for (i = 0; i < nnameservers; i++) { addr = nm_ip4_config_get_nameserver (ip4, i); - add_dnsmasq_nameserver (servers, + add_dnsmasq_nameserver (self, servers, nm_utils_inet4_ntop (addr, NULL), NULL); } } @@ -177,7 +178,7 @@ ip6_addr_to_string (const struct in6_addr *addr, const char *iface) } static void -add_global_config (GVariantBuilder *dnsmasq_servers, const NMGlobalDnsConfig *config) +add_global_config (NMDnsDnsmasq *self, GVariantBuilder *dnsmasq_servers, const NMGlobalDnsConfig *config) { guint i, j; @@ -192,16 +193,16 @@ add_global_config (GVariantBuilder *dnsmasq_servers, const NMGlobalDnsConfig *co for (j = 0; servers && servers[j]; j++) { if (!strcmp (name, "*")) - add_dnsmasq_nameserver (dnsmasq_servers, servers[j], NULL); + add_dnsmasq_nameserver (self, dnsmasq_servers, servers[j], NULL); else - add_dnsmasq_nameserver (dnsmasq_servers, servers[j], name); + add_dnsmasq_nameserver (self, dnsmasq_servers, servers[j], name); } } } static gboolean -add_ip6_config (GVariantBuilder *servers, NMIP6Config *ip6, gboolean split) +add_ip6_config (NMDnsDnsmasq *self, GVariantBuilder *servers, NMIP6Config *ip6, gboolean split) { const struct in6_addr *addr; char *buf = NULL; @@ -225,7 +226,8 @@ add_ip6_config (GVariantBuilder *servers, NMIP6Config *ip6, gboolean split) /* searches are preferred over domains */ n = nm_ip6_config_get_num_searches (ip6); for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (servers, + add_dnsmasq_nameserver (self, + servers, buf, nm_ip6_config_get_search (ip6, i)); added = TRUE; @@ -235,7 +237,8 @@ add_ip6_config (GVariantBuilder *servers, NMIP6Config *ip6, gboolean split) /* If not searches, use any domains */ n = nm_ip6_config_get_num_domains (ip6); for (i = 0; i < n; i++) { - add_dnsmasq_nameserver (servers, + add_dnsmasq_nameserver (self, + servers, buf, nm_ip6_config_get_domain (ip6, i)); added = TRUE; @@ -252,7 +255,7 @@ add_ip6_config (GVariantBuilder *servers, NMIP6Config *ip6, gboolean split) addr = nm_ip6_config_get_nameserver (ip6, i); buf = ip6_addr_to_string (addr, iface); if (buf) { - add_dnsmasq_nameserver (servers, buf, NULL); + add_dnsmasq_nameserver (self, servers, buf, NULL); g_free (buf); } } @@ -266,50 +269,38 @@ dnsmasq_update_done (GObject *source, GAsyncResult *res, gpointer user_data) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); - GError *error = NULL; - GVariant *response; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *response = NULL; response = g_dbus_proxy_call_finish (priv->dnsmasq, res, &error); - if (error) { - nm_log_warn (LOGD_DNS, "Dnsmasq update failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - } - - if (response) - g_variant_unref (response); + if (!response) + _LOGW ("dnsmasq update failed: %s", error->message); + else + _LOGD ("dnsmasq update successful"); } -static gboolean +static void send_dnsmasq_update (NMDnsDnsmasq *self) { NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); - nm_log_dbg (LOGD_DNS, "trying to update dnsmasq nameservers"); - - if (!priv->servers) { - nm_log_warn (LOGD_DNS, "no nameservers list to send update"); - return FALSE; - } + if (!priv->set_server_ex_args) + return; if (priv->running) { + _LOGD ("trying to update dnsmasq nameservers"); + g_dbus_proxy_call (priv->dnsmasq, "SetServersEx", - g_variant_new ("(aas)", - priv->servers), + priv->set_server_ex_args, G_DBUS_CALL_FLAGS_NONE, -1, NULL, (GAsyncReadyCallback) dnsmasq_update_done, self); - g_variant_builder_unref (priv->servers); - priv->servers = NULL; - } else { - nm_log_warn (LOGD_DNS, "Dnsmasq not found on the bus."); - nm_log_warn (LOGD_DNS, "The nameserver update will be sent when dnsmasq appears."); - } - - return TRUE; + g_clear_pointer (&priv->set_server_ex_args, g_variant_unref); + } else + _LOGD ("dnsmasq not found on the bus. The nameserver update will be sent when dnsmasq appears"); } static void @@ -323,11 +314,11 @@ name_owner_changed (GObject *object, owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); if (owner) { - nm_log_info (LOGD_DNS, "dnsmasq appeared as %s", owner); + _LOGI ("dnsmasq appeared as %s", owner); priv->running = TRUE; - g_signal_emit_by_name (self, NM_DNS_PLUGIN_APPEARED); + send_dnsmasq_update (self); } else { - nm_log_info (LOGD_DNS, "dnsmasq disappeared"); + _LOGI ("dnsmasq disappeared"); priv->running = FALSE; g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); } @@ -336,103 +327,64 @@ name_owner_changed (GObject *object, static void dnsmasq_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) { - NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data); - NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); - GError *error = NULL; + NMDnsDnsmasq *self; + NMDnsDnsmasqPrivate *priv; + gs_free_error GError *error = NULL; gs_free char *owner = NULL; + GDBusProxy *proxy; - nm_log_dbg (LOGD_DNS, "dnsmasq proxy creation returned"); + proxy = g_dbus_proxy_new_finish (res, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - if (priv->dnsmasq) { - nm_log_dbg (LOGD_DNS, "already have an old proxy; replacing."); - g_object_unref (priv->dnsmasq); - priv->dnsmasq = NULL; + self = NM_DNS_DNSMASQ (user_data); + + if (!proxy) { + _LOGW ("failed to connect to dnsmasq via DBus: %s", error->message); + g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); + return; } - priv->dnsmasq = g_dbus_proxy_new_finish (res, &error); - if (!priv->dnsmasq) { - nm_log_warn (LOGD_DNS, "Failed to connect to dnsmasq via DBus: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - } else { - nm_log_dbg (LOGD_DNS, "dnsmasq proxy creation successful"); + priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); - g_signal_connect (priv->dnsmasq, "notify::g-name-owner", - G_CALLBACK (name_owner_changed), self); - owner = g_dbus_proxy_get_name_owner (priv->dnsmasq); - priv->running = (owner != NULL); + priv->dnsmasq = proxy; + nm_clear_g_cancellable (&priv->dnsmasq_cancellable); - if (priv->running && priv->servers) - send_dnsmasq_update (self); - } + _LOGD ("dnsmasq proxy creation successful"); + + g_signal_connect (priv->dnsmasq, "notify::g-name-owner", + G_CALLBACK (name_owner_changed), self); + owner = g_dbus_proxy_get_name_owner (priv->dnsmasq); + priv->running = (owner != NULL); + + if (priv->running) + send_dnsmasq_update (self); } static void -get_dnsmasq_proxy (NMDnsDnsmasq *self) -{ - NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); - - g_return_if_fail (!priv->dnsmasq); - - nm_log_dbg (LOGD_DNS, "retrieving dnsmasq proxy"); - - if (!priv->dnsmasq) { - g_dbus_proxy_new (priv->connection, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - DNSMASQ_DBUS_SERVICE, - DNSMASQ_DBUS_PATH, - DNSMASQ_DBUS_SERVICE, - NULL, - dnsmasq_proxy_cb, - self); - } -} - -static gboolean start_dnsmasq (NMDnsDnsmasq *self) { NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); const char *dm_binary; const char *argv[15]; - GError *error = NULL; - int ignored; GPid pid = 0; guint idx = 0; - GString *conf; + NMBusManager *dbus_mgr; + GDBusConnection *connection; - /* dnsmasq is probably already started; if it's the case, don't do - * anything more. - */ - if (priv->running) { - nm_log_dbg (LOGD_DNS, "dnsmasq is already running"); - return TRUE; - } - /* Start dnsmasq */ + if ( priv->running + || priv->dnsmasq + || priv->dnsmasq_cancellable) + return; dm_binary = nm_utils_find_helper ("dnsmasq", DNSMASQ_PATH, NULL); if (!dm_binary) { _LOGW ("could not find dnsmasq binary"); - return FALSE; + return; } - /* Build up the new dnsmasq config file */ - conf = g_string_sized_new (150); - - /* Write out the config file */ - if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) { - _LOGW ("failed to write dnsmasq config file %s: %s", - CONFFILE, - error->message); - g_clear_error (&error); - goto out; - } - ignored = chmod (CONFFILE, 0644); - - _LOGD ("dnsmasq local caching DNS configuration:"); - _LOGD ("%s", conf->str); - argv[idx++] = dm_binary; argv[idx++] = "--no-resolv"; /* Use only commandline */ argv[idx++] = "--keep-in-foreground"; @@ -440,7 +392,6 @@ start_dnsmasq (NMDnsDnsmasq *self) argv[idx++] = "--bind-interfaces"; argv[idx++] = "--pid-file=" PIDFILE; argv[idx++] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */ - argv[idx++] = "--conf-file=" CONFFILE; argv[idx++] = "--cache-size=400"; argv[idx++] = "--proxy-dnssec"; /* Allow DNSSEC to pass through */ argv[idx++] = "--enable-dbus=" DNSMASQ_DBUS_SERVICE; @@ -450,16 +401,29 @@ start_dnsmasq (NMDnsDnsmasq *self) argv[idx++] = "--conf-dir=" CONFDIR; argv[idx++] = NULL; - g_warn_if_fail (idx <= G_N_ELEMENTS (argv)); + nm_assert (idx <= G_N_ELEMENTS (argv)); /* And finally spawn dnsmasq */ pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq"); + if (!pid) + return; - if (pid && !priv->dnsmasq) - get_dnsmasq_proxy (self); -out: - g_string_free (conf, TRUE); - return pid ? TRUE : FALSE; + dbus_mgr = nm_bus_manager_get (); + g_return_if_fail (dbus_mgr); + + connection = nm_bus_manager_get_connection (dbus_mgr); + g_return_if_fail (connection); + + priv->dnsmasq_cancellable = g_cancellable_new (); + g_dbus_proxy_new (connection, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + DNSMASQ_DBUS_SERVICE, + DNSMASQ_DBUS_PATH, + DNSMASQ_DBUS_SERVICE, + priv->dnsmasq_cancellable, + dnsmasq_proxy_cb, + self); } static gboolean @@ -472,58 +436,47 @@ update (NMDnsPlugin *plugin, { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); - GSList *iter; - GError *error = NULL; - gboolean ret = FALSE; + const GSList *iter; + GVariantBuilder servers; - if (!priv->running) - start_dnsmasq (self); + start_dnsmasq (self); - if (priv->servers) - g_variant_builder_unref (priv->servers); - priv->servers = g_variant_builder_new (G_VARIANT_TYPE ("aas")); + g_variant_builder_init (&servers, G_VARIANT_TYPE ("aas")); if (global_config) - add_global_config (priv->servers, global_config); + add_global_config (self, &servers, global_config); else { /* Use split DNS for VPN configs */ - for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) { + for (iter = vpn_configs; iter; iter = g_slist_next (iter)) { if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (priv->servers, NM_IP4_CONFIG (iter->data), TRUE); + add_ip4_config (self, &servers, iter->data, TRUE); else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (priv->servers, NM_IP6_CONFIG (iter->data), TRUE); + add_ip6_config (self, &servers, iter->data, TRUE); } /* Now add interface configs without split DNS */ - for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) { + for (iter = dev_configs; iter; iter = g_slist_next (iter)) { if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (priv->servers, NM_IP4_CONFIG (iter->data), FALSE); + add_ip4_config (self, &servers, iter->data, FALSE); else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (priv->servers, NM_IP6_CONFIG (iter->data), FALSE); + add_ip6_config (self, &servers, iter->data, FALSE); } /* And any other random configs */ - for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) { + for (iter = other_configs; iter; iter = g_slist_next (iter)) { if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (priv->servers, NM_IP4_CONFIG (iter->data), FALSE); + add_ip4_config (self, &servers, iter->data, FALSE); else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (priv->servers, NM_IP6_CONFIG (iter->data), FALSE); + add_ip6_config (self, &servers, iter->data, FALSE); } } - ret = send_dnsmasq_update (self); + g_clear_pointer (&priv->set_server_ex_args, g_variant_unref); + priv->set_server_ex_args = g_variant_ref_sink (g_variant_new ("(aas)", &servers)); - /* If all the configs lists are empty, there is just nothing to be caching -- - * we cleared up the dnsmasq cache; but we should also fail the update, so - * that we don't write 127.0.0.1 to resolv.conf. - */ - if (((vpn_configs && g_slist_length ((GSList *) vpn_configs) < 1) || !vpn_configs) && - ((dev_configs && g_slist_length ((GSList *) dev_configs) < 1) || !dev_configs) && - ((other_configs && g_slist_length ((GSList *) other_configs) < 1) || !other_configs)) - ret = FALSE; + send_dnsmasq_update (self); -out: - return ret; + return TRUE; } /****************************************************************/ @@ -567,7 +520,6 @@ child_quit (NMDnsPlugin *plugin, gint status) _LOGW ("dnsmasq died with signal %d", WTERMSIG (status)); else _LOGW ("dnsmasq died from an unknown cause"); - unlink (CONFFILE); if (failed) g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); @@ -598,18 +550,6 @@ nm_dns_dnsmasq_new (void) static void nm_dns_dnsmasq_init (NMDnsDnsmasq *self) { - NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); - - priv->dbus_mgr = nm_bus_manager_get (); - priv->running = FALSE; - - g_assert (priv->dbus_mgr); - - priv->connection = nm_bus_manager_get_connection (priv->dbus_mgr); - if (!priv->connection) - nm_log_warn (LOGD_DNS, "Could not get the system bus to speak to dnsmasq."); - else - get_dnsmasq_proxy (self); } static void @@ -617,12 +557,11 @@ dispose (GObject *object) { NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (object); - unlink (CONFFILE); + nm_clear_g_cancellable (&priv->dnsmasq_cancellable); - if (priv->dbus_mgr) { - g_object_unref (priv->dbus_mgr); - priv->dbus_mgr = NULL; - } + g_clear_object (&priv->dnsmasq); + + g_clear_pointer (&priv->set_server_ex_args, g_variant_unref); G_OBJECT_CLASS (nm_dns_dnsmasq_parent_class)->dispose (object); } diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index f65e8d11d1..b42af167cd 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -1064,27 +1064,6 @@ update_dns (NMDnsManager *self, return !update || result == SR_SUCCESS; } -static void -plugin_appeared (NMDnsPlugin *plugin, gpointer user_data) -{ - NMDnsManager *self = NM_DNS_MANAGER (user_data); - NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - GError *error = NULL; - - /* Not applicable to non-caching plugins */ - if (!nm_dns_plugin_is_caching (plugin)) - return; - - /* Try to update DNS again; since it's now available on the bus this - * might work. */ - if (!update_dns (self, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } -} - static void plugin_failed (NMDnsPlugin *plugin, gpointer user_data) { @@ -1453,7 +1432,6 @@ init_resolv_conf_mode (NMDnsManager *self) g_signal_connect (priv->plugin, NM_DNS_PLUGIN_FAILED, G_CALLBACK (plugin_failed), self); g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self); - g_signal_connect (priv->plugin, NM_DNS_PLUGIN_APPEARED, G_CALLBACK (plugin_appeared), self); _NMLOG (immutable ? LOGL_WARN : LOGL_INFO, "%s%s%s%s%s%s", diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index 76c7c3e63c..d5cb882246 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -43,7 +43,6 @@ G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_A enum { FAILED, - APPEARED, CHILD_QUIT, LAST_SIGNAL }; @@ -286,15 +285,6 @@ nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - signals[APPEARED] = - g_signal_new (NM_DNS_PLUGIN_APPEARED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDnsPluginClass, failed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[CHILD_QUIT] = g_signal_new (NM_DNS_PLUGIN_CHILD_QUIT, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h index 6ed5b1bcc0..7ecaa424dc 100644 --- a/src/dns-manager/nm-dns-plugin.h +++ b/src/dns-manager/nm-dns-plugin.h @@ -31,7 +31,6 @@ #define NM_DNS_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass)) #define NM_DNS_PLUGIN_FAILED "failed" -#define NM_DNS_PLUGIN_APPEARED "appeared" #define NM_DNS_PLUGIN_CHILD_QUIT "child-quit" #define IP_CONFIG_IFACE_TAG "dns-manager-iface" From 3341365e29437e81776e179280f1d3167dd7992c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 21 Apr 2016 19:06:46 +0200 Subject: [PATCH 7/7] dns: avoid using global "/etc/dnsmasq.conf" config for dnsmasq Pass an empty configuration file otherwise dnsmasq loads "/etc/dnsmasq.conf". We already allow for a config.d/ directory "/etc/NetworkManager/dnsmasq.d" to allow the user to overwrite configuration. We don't want to consider the global config file. Fixes: 497a8aa5c6463404200a3fcc745aa65396dc4f22 (cherry picked from commit 3d3f71acec5c59a8e01a4d1b0897183fbc49f57c) --- src/dns-manager/nm-dns-dnsmasq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c index 77ac548d8c..4cee160890 100644 --- a/src/dns-manager/nm-dns-dnsmasq.c +++ b/src/dns-manager/nm-dns-dnsmasq.c @@ -393,6 +393,7 @@ start_dnsmasq (NMDnsDnsmasq *self) argv[idx++] = "--pid-file=" PIDFILE; argv[idx++] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */ argv[idx++] = "--cache-size=400"; + argv[idx++] = "--conf-file=/dev/null"; /* avoid loading /etc/dnsmasq.conf */ argv[idx++] = "--proxy-dnssec"; /* Allow DNSSEC to pass through */ argv[idx++] = "--enable-dbus=" DNSMASQ_DBUS_SERVICE;