---
 src/dns-manager/nm-dns-dnsmasq.c |  337 ++++++++++++++++++++++++--------------
 src/dns-manager/nm-dns-plugin.c  |    6 +
 2 files changed, 219 insertions(+), 124 deletions(-)

diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c
index 9090e26..7ddc4f6 100644
--- a/src/dns-manager/nm-dns-dnsmasq.c
+++ b/src/dns-manager/nm-dns-dnsmasq.c
@@ -29,11 +29,16 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+
 #include "nm-dns-dnsmasq.h"
 #include "nm-logging.h"
 #include "nm-ip4-config.h"
 #include "nm-ip6-config.h"
 #include "nm-dns-utils.h"
+#include "nm-dbus-manager.h"
 
 G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
 
@@ -43,8 +48,13 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, 
NM_TYPE_DNS_PLUGIN)
 #define CONFFILE LOCALSTATEDIR "/run/nm-dns-dnsmasq.conf"
 #define CONFDIR SYSCONFDIR "/NetworkManager/dnsmasq.d"
 
+#define DNSMASQ_DBUS_SERVICE "uk.org.thekelleys.dnsmasq"
+#define DNSMASQ_DBUS_PATH "/uk/org/thekelleys/dnsmasq"
+#define DNSMASQ_DBUS_INTERFACE "uk.org.thekelleys.dnsmasq"
+
 typedef struct {
-       guint32 foo;
+       NMDBusManager *dbus_mgr;
+       guint name_owner_id;
 } NMDnsDnsmasqPrivate;
 
 /*******************************************/
@@ -69,12 +79,11 @@ find_dnsmasq (void)
 }
 
 static gboolean
-add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split)
+add_ip4_config (DBusMessage *message, NMIP4Config *ip4, gboolean split)
 {
-       char buf[INET_ADDRSTRLEN + 1];
-       struct in_addr addr;
        int n, i;
        gboolean added = FALSE;
+       guint32 addr;
 
        if (split) {
                char **domains, **iter;
@@ -83,17 +92,17 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean 
split)
                 * per domain (and the manpage says this too) so only use the 
first
                 * nameserver here.
                 */
-               addr.s_addr = nm_ip4_config_get_nameserver (ip4, 0);
-               memset (&buf[0], 0, sizeof (buf));
-               if (!inet_ntop (AF_INET, &addr, buf, sizeof (buf)))
-                       return FALSE;
+               addr = g_htonl(nm_ip4_config_get_nameserver (ip4, 0));
+               dbus_message_append_args (message,
+                                         DBUS_TYPE_UINT32, &addr,
+                                         DBUS_TYPE_INVALID);
 
                /* 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);
+                       dbus_message_append_args (message,
+                                                 DBUS_TYPE_STRING, 
nm_ip4_config_get_search (ip4, i),
+                                                 DBUS_TYPE_INVALID);
                        added = TRUE;
                }
 
@@ -101,9 +110,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);
+                               dbus_message_append_args (message,
+                                                         DBUS_TYPE_STRING, 
nm_ip4_config_get_domain (ip4, i),
+                                                         DBUS_TYPE_INVALID);
                                added = TRUE;
                        }
                }
@@ -114,7 +123,9 @@ 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);
+                               dbus_message_append_args (message,
+                                                         DBUS_TYPE_STRING, 
*iter,
+                                                         DBUS_TYPE_INVALID);
                        g_strfreev (domains);
                        added = TRUE;
                }
@@ -124,66 +135,20 @@ add_ip4_config (GString *str, NMIP4Config *ip4, gboolean 
split)
        if (!added) {
                n = nm_ip4_config_get_num_nameservers (ip4);
                for (i = 0; i < n; i++) {
-                       memset (&buf[0], 0, sizeof (buf));
-                       addr.s_addr = nm_ip4_config_get_nameserver (ip4, i);
-                       if (inet_ntop (AF_INET, &addr, buf, sizeof (buf)))
-                               g_string_append_printf (str, "server=%s\n", 
buf);
+                       addr = g_htonl(nm_ip4_config_get_nameserver (ip4, i));
+                       dbus_message_append_args (message,
+                                                 DBUS_TYPE_UINT32, &addr,
+                                                 DBUS_TYPE_INVALID);
                }
        }
 
        return TRUE;
 }
 
-#define IP6_ADDR_BUFLEN (INET6_ADDRSTRLEN + 50)
-
-static char *
-ip6_addr_to_string (const struct in6_addr *addr, const char *iface)
-{
-       char *buf, *p;
-
-       /* allocate enough space for the address + interface name */
-       buf = g_malloc0 (IP6_ADDR_BUFLEN + 1);
-
-       /* inet_ntop is probably supposed to do this for us, but it doesn't */
-       if (IN6_IS_ADDR_V4MAPPED (addr)) {
-               if (!inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, 
IP6_ADDR_BUFLEN))
-                       goto error;
-               return buf;
-       }
-
-       if (!inet_ntop (AF_INET6, addr, buf, IP6_ADDR_BUFLEN))
-               goto error;
-
-       /* In the case of addr being a link-local address, inet_ntop can either
-        * return an address with scope identifier already in place (like
-        * fe80::202:b3ff:fe8d:7aaf%wlan0) or it returns an address without
-        * scope identifier at all (like fe80::202:b3ff:fe8d:7aaf)
-        */
-       p = strchr (buf, '%');
-       if (p) {
-               /* If we got a scope identifier, we need to replace the '%'
-                * with '@', since dnsmasq supports '%' in server= addresses
-                * only since version 2.58 and up
-                */
-               *p = '@';
-       } else if (IN6_IS_ADDR_LINKLOCAL (addr)) {
-               /* If we got no scope identifier at all append the interface 
name */
-               strncat (buf, "@", IP6_ADDR_BUFLEN - strlen (buf));
-               strncat (buf, iface, IP6_ADDR_BUFLEN - strlen (buf));
-       }
-
-       return buf;
-
-error:
-       g_free (buf);
-       return NULL;
-}
-
 static gboolean
-add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char 
*iface)
+add_ip6_config (DBusMessage *message, NMIP6Config *ip6, gboolean split, const 
char *iface)
 {
        const struct in6_addr *addr;
-       char *buf;
        int n, i;
        gboolean added = FALSE;
 
@@ -193,16 +158,31 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean 
split, const char *ifac
                 * the first nameserver here.
                 */
                addr = nm_ip6_config_get_nameserver (ip6, 0);
-               buf = ip6_addr_to_string (addr, iface);
-               if (!buf)
-                       return FALSE;
+               dbus_message_append_args (message,
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[0],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[1],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[2],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[3],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[4],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[5],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[6],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[7],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[8],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[9],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[10],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[11],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[12],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[13],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[14],
+                                         DBUS_TYPE_BYTE, &addr->s6_addr[15],
+                                         DBUS_TYPE_INVALID);
 
                /* 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);
+                       dbus_message_append_args (message,
+                                                 DBUS_TYPE_STRING, 
nm_ip6_config_get_search (ip6, i),
+                                                 DBUS_TYPE_INVALID);
                        added = TRUE;
                }
 
@@ -210,14 +190,12 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean 
split, const char *ifac
                        /* 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);
+                               dbus_message_append_args (message,
+                                                         DBUS_TYPE_STRING, 
nm_ip6_config_get_domain (ip6, i),
+                                                         DBUS_TYPE_INVALID);
                                added = TRUE;
                        }
                }
-
-               g_free (buf);
        }
 
        /* If no searches or domains, just add the namservers */
@@ -225,11 +203,24 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean 
split, const char *ifac
                n = nm_ip6_config_get_num_nameservers (ip6);
                for (i = 0; i < n; i++) {
                        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);
-                               g_free (buf);
-                       }
+                       dbus_message_append_args (message,
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[0],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[1],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[2],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[3],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[4],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[5],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[6],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[7],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[8],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[9],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[10],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[11],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[12],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[13],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[14],
+                                                 DBUS_TYPE_BYTE, 
&addr->s6_addr[15],
+                                                 DBUS_TYPE_INVALID);
                }
        }
 
@@ -237,55 +228,28 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean 
split, const char *ifac
 }
 
 static gboolean
-update (NMDnsPlugin *plugin,
-        const GSList *vpn_configs,
-        const GSList *dev_configs,
-        const GSList *other_configs,
-        const char *hostname,
-        const char *iface)
+start_dnsmasq (NMDnsDnsmasq *self)
 {
-       NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
-       GString *conf;
-       GSList *iter;
-       const char *argv[12];
+       NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
+       const char *argv[13];
+       char *dnsmasq_owner;
        GError *error = NULL;
-       int ignored;
+       GString *conf;
        GPid pid = 0;
+       int ignored;
 
-       /* 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);
+       dnsmasq_owner = nm_dbus_manager_get_name_owner (priv->dbus_mgr, 
DNSMASQ_DBUS_SERVICE, NULL);
+       if (dnsmasq_owner != NULL)
+               return TRUE;
+
+       /* Start dnsmasq */
 
        /* 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",
@@ -310,8 +274,10 @@ update (NMDnsPlugin *plugin,
        argv[7] = "--conf-file=" CONFFILE;
        argv[8] = "--cache-size=400";
        argv[9] = "--proxy-dnssec"; /* Allow DNSSEC to pass through */
-       argv[10] = "--conf-dir=" CONFDIR;
-       argv[11] = NULL;
+       argv[10] = "--enable-dbus";
+       argv[11] = "--conf-dir=" CONFDIR;
+       argv[12] = NULL;
+
 
        /* And finally spawn dnsmasq */
        pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, 
"bin/dnsmasq");
@@ -321,8 +287,113 @@ out:
        return pid ? TRUE : FALSE;
 }
 
+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);
+       NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
+       DBusConnection *connection;
+       DBusMessage *message = NULL;
+       GSList *iter;
+       GError *error = NULL;
+       gboolean have_dnsmasq = FALSE;
+       gboolean ret = FALSE;
+       dbus_bool_t result;
+
+       have_dnsmasq = start_dnsmasq (self);
+
+       if (!have_dnsmasq)
+               goto out;
+
+       connection = nm_dbus_manager_get_dbus_connection (priv->dbus_mgr);
+       if (!connection) {
+               nm_log_warn (LOGD_DNS, "Could not get the system bus to speak 
to dnsmasq.");
+               goto out;
+       }
+
+       message = dbus_message_new_method_call (DNSMASQ_DBUS_SERVICE, 
DNSMASQ_DBUS_PATH,
+                                               DNSMASQ_DBUS_INTERFACE, 
"SetServers");
+
+       /* 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 (message, NM_IP4_CONFIG (iter->data), 
TRUE);
+               else if (NM_IS_IP6_CONFIG (iter->data))
+                       add_ip6_config (message, 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 (message, NM_IP4_CONFIG (iter->data), 
FALSE);
+               else if (NM_IS_IP6_CONFIG (iter->data))
+                       add_ip6_config (message, 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 (message, NM_IP4_CONFIG (iter->data), 
FALSE);
+               else if (NM_IS_IP6_CONFIG (iter->data))
+                       add_ip6_config (message, NM_IP6_CONFIG (iter->data), 
FALSE, iface);
+       }
+
+       if (!nm_dbus_manager_get_name_owner (priv->dbus_mgr, 
DNSMASQ_DBUS_SERVICE, &error)) {
+               nm_log_err (LOGD_DNS, "dnsmasq not available on the bus, can't 
update servers.");
+               if (error)
+                       nm_log_err (LOGD_DNS, "dnsmasq owner not found on bus: 
%s", error->message);
+               goto out;
+       }
+
+       result = dbus_connection_send (connection, message, NULL);
+       if (!result) {
+               nm_log_err (LOGD_DNS, "Could not send dnsmasq SetServers 
method.");
+               goto out;
+       }
+
+       ret = TRUE;
+
+out:
+       if (message)
+               dbus_message_unref (message);
+
+       return ret;
+}
+
 /****************************************************************/
 
+static void
+name_owner_changed_cb (NMDBusManager *dbus_mgr,
+                       const char *name,
+                       const char *old_owner,
+                       const char *new_owner,
+                       gpointer user_data)
+{
+       NMDnsDnsmasq *self = NM_DNS_DNSMASQ (user_data);
+       gboolean old_owner_good = (old_owner && strlen (old_owner));
+       gboolean new_owner_good = (new_owner && strlen (new_owner));
+
+       /* Can't handle the signal if its not from dnsmasq */
+       if (strcmp (DNSMASQ_DBUS_SERVICE, name))
+               return;
+
+       if (!old_owner_good && new_owner_good) {
+               nm_log_warn (LOGD_DNS, "dnsmasq appeared on DBus: %s",
+                            new_owner);
+       } else if (old_owner_good && new_owner_good) {
+               nm_log_dbg (LOGD_DNS, "DBus name owner for dnsmasq changed: %s 
-> %s",
+                            old_owner, new_owner);
+       } else {
+               nm_log_warn (LOGD_DNS, "dnsmasq disappeared from the bus.");
+               g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED);
+       }
+}
+
 static const char *
 dm_exit_code_to_msg (int status)
 {
@@ -400,13 +471,31 @@ 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_dbus_manager_get ();
+
+       g_assert (priv->dbus_mgr);
+
+       priv->name_owner_id = g_signal_connect (priv->dbus_mgr,
+                                               
NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
+                                               G_CALLBACK 
(name_owner_changed_cb),
+                                               self);
 }
 
 static void
 dispose (GObject *object)
 {
+       NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (object);
+
        unlink (CONFFILE);
 
+       if (priv->dbus_mgr) {
+               if (priv->name_owner_id)
+                       g_signal_handler_disconnect (priv->dbus_mgr, 
priv->name_owner_id);
+               g_object_unref (priv->dbus_mgr);
+       }
+
        G_OBJECT_CLASS (nm_dns_dnsmasq_parent_class)->dispose (object);
 }
 
diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c
index b26f2b9..8f86d98 100644
--- a/src/dns-manager/nm-dns-plugin.c
+++ b/src/dns-manager/nm-dns-plugin.c
@@ -133,6 +133,12 @@ watch_cb (GPid pid, gint status, gpointer user_data)
        g_free (priv->progname);
        priv->progname = NULL;
 
+       if (priv->pidfile) {
+               unlink (priv->pidfile);
+               g_free (priv->pidfile);
+               priv->pidfile = NULL;
+       }
+
        g_signal_emit (self, signals[CHILD_QUIT], 0, status);
 }
 
-- 
1.7.10.4

_______________________________________________
networkmanager-list mailing list
[email protected]
https://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to