static void child_quit (NMDnsPlugin *plugin, gint status) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); gboolean failed = TRUE; int err; if (WIFEXITED (status)) { err = WEXITSTATUS (status); if (err) { _LOGW ("dnsmasq exited with error: %s", nm_utils_dnsmasq_status_to_string (err, NULL, 0)); } else { _LOGD ("dnsmasq exited normally"); failed = FALSE; } } else if (WIFSTOPPED (status)) _LOGW ("dnsmasq stopped unexpectedly with signal %d", WSTOPSIG (status)); else if (WIFSIGNALED (status)) _LOGW ("dnsmasq died with signal %d", WTERMSIG (status)); else _LOGW ("dnsmasq died from an unknown cause"); priv->running = FALSE; if (failed) g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); }
static void child_quit (NMDnsPlugin *plugin, gint status) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); gboolean failed = TRUE; int err; if (WIFEXITED (status)) { err = WEXITSTATUS (status); if (err) { nm_log_warn (LOGD_DNS, "dnsmasq exited with error: %s (%d)", dm_exit_code_to_msg (err), err); } else failed = FALSE; } else if (WIFSTOPPED (status)) { nm_log_warn (LOGD_DNS, "dnsmasq stopped unexpectedly with signal %d", WSTOPSIG (status)); } else if (WIFSIGNALED (status)) { nm_log_warn (LOGD_DNS, "dnsmasq died with signal %d", WTERMSIG (status)); } else { nm_log_warn (LOGD_DNS, "dnsmasq died from an unknown cause"); } unlink (CONFFILE); if (failed) g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); }
static gboolean update (NMDnsPlugin *plugin, const NMDnsIPConfigData **configs, const NMGlobalDnsConfig *global_config, const char *hostname) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); GVariantBuilder servers; start_dnsmasq (self); g_variant_builder_init (&servers, G_VARIANT_TYPE ("aas")); if (global_config) add_global_config (self, &servers, global_config); else { while (*configs) { add_ip_config_data (self, &servers, *configs); configs++; } } 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)); send_dnsmasq_update (self); return TRUE; }
static void dnsmasq_update_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) { NMDnsDnsmasq *self; NMDnsDnsmasqPrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *response = NULL; response = g_dbus_proxy_call_finish (proxy, res, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; self = NM_DNS_DNSMASQ (user_data); priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); if (!response) _LOGW ("dnsmasq update failed: %s", error->message); else { g_dbus_proxy_call (priv->dnsmasq, "ClearCache", NULL, G_DBUS_CALL_FLAGS_NONE, -1, priv->update_cancellable, (GAsyncReadyCallback) dnsmasq_clear_cache_done, self); } }
static void dnsmasq_clear_cache_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) { NMDnsDnsmasq *self; gs_free_error GError *error = NULL; gs_unref_variant GVariant *response = NULL; response = g_dbus_proxy_call_finish (proxy, res, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; self = NM_DNS_DNSMASQ (user_data); if (!response) _LOGW ("dnsmasq cache clear failed: %s", error->message); else _LOGD ("dnsmasq update successful, cache cleared"); }
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) { _LOGI ("dnsmasq appeared as %s", owner); priv->running = TRUE; send_dnsmasq_update (self); } else { _LOGI ("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; NMDnsDnsmasqPrivate *priv; gs_free_error GError *error = NULL; gs_free char *owner = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_finish (res, &error); if ( !proxy && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; 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 = NM_DNS_DNSMASQ_GET_PRIVATE (self); priv->dnsmasq = proxy; nm_clear_g_cancellable (&priv->dnsmasq_cancellable); _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 gboolean update (NMDnsPlugin *plugin, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, const char *hostname, const char *iface) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); GString *conf; GSList *iter; const char *argv[11]; GError *error = NULL; int ignored; GPid pid = 0; /* 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. */ nm_dns_plugin_child_kill (plugin); /* Build up the new dnsmasq config file */ conf = g_string_sized_new (150); /* 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, iface); } /* 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, iface); } /* 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, iface); } /* Write out the config file */ if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) { nm_log_warn (LOGD_DNS, "Failed to write dnsmasq config file %s: (%d) %s", CONFFILE, error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_clear_error (&error); goto out; } ignored = chmod (CONFFILE, 0600); nm_log_dbg (LOGD_DNS, "dnsmasq local caching DNS configuration:"); nm_log_dbg (LOGD_DNS, "%s", conf->str); argv[0] = find_dnsmasq (); argv[1] = "--no-resolv"; /* Use only commandline */ argv[2] = "--keep-in-foreground"; argv[3] = "--strict-order"; argv[4] = "--bind-interfaces"; argv[5] = "--pid-file=" PIDFILE; argv[6] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */ argv[7] = "--conf-file=" CONFFILE; argv[8] = "--cache-size=400"; argv[9] = NULL; /* And finally spawn dnsmasq */ pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq"); 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); const char *dm_binary; GString *conf; GSList *iter; const char *argv[15]; GError *error = NULL; int ignored; GPid pid = 0; guint idx = 0; /* 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. */ nm_dns_plugin_child_kill (plugin); dm_binary = nm_utils_find_helper ("dnsmasq", DNSMASQ_PATH, NULL); if (!dm_binary) { nm_log_warn (LOGD_DNS, "Could not find dnsmasq binary"); return FALSE; } /* 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)) { nm_log_warn (LOGD_DNS, "Failed to write dnsmasq config file %s: (%d) %s", CONFFILE, error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_clear_error (&error); goto out; } ignored = chmod (CONFFILE, 0644); nm_log_dbg (LOGD_DNS, "dnsmasq local caching DNS configuration:"); nm_log_dbg (LOGD_DNS, "%s", conf->str); argv[idx++] = dm_binary; argv[idx++] = "--no-resolv"; /* Use only commandline */ argv[idx++] = "--keep-in-foreground"; argv[idx++] = "--no-hosts"; /* don't use /etc/hosts to resolve */ 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 */ /* dnsmasq exits if the conf dir is not present */ if (g_file_test (CONFDIR, G_FILE_TEST_IS_DIR)) argv[idx++] = "--conf-dir=" CONFDIR; argv[idx++] = NULL; g_warn_if_fail (idx <= G_N_ELEMENTS (argv)); /* And finally spawn dnsmasq */ pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq"); out: g_string_free (conf, TRUE); return pid ? TRUE : FALSE; }