dnsmasq DBUS integration



Just refreshing a patch I posted here before...
http://mail.gnome.org/archives/networkmanager-list/2011-January/msg00029.html
https://bugzilla.gnome.org/show_bug.cgi?id=551747

I don't see any conflict with libvirt, since that dnsmasq instance is running with its own private dnsmasq.conf already.

This patch is relative to current git master, but also applies cleanly to the 0.9.1 source used in current Ubuntu 12.x.

As with this poster http://mail.gnome.org/archives/networkmanager-list/2011-January/msg00024.html I just want NM to leave /etc/resolv.conf alone.

--
  -- Howard Chu
  CTO, Symas Corp.           http://www.symas.com
  Director, Highland Sun     http://highlandsun.com/hyc/
  Chief Architect, OpenLDAP  http://www.openldap.org/project/
>From 85595070b621e3977bd8af263d1e6fb186279322 Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc symas com>
Date: Wed, 18 Apr 2012 07:01:13 -0700
Subject: [PATCH] Control dnsmasq using DBUS

---
 src/dns-manager/Makefile.am      |    1 +
 src/dns-manager/nm-dns-dnsmasq.c |  213 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 213 insertions(+), 1 deletions(-)

diff --git a/src/dns-manager/Makefile.am b/src/dns-manager/Makefile.am
index 331f85c..8f9233f 100644
--- a/src/dns-manager/Makefile.am
+++ b/src/dns-manager/Makefile.am
@@ -24,6 +24,7 @@ libdns_manager_la_CPPFLAGS = \
 	$(LIBNL_CFLAGS) \
 	$(DBUS_CFLAGS) \
 	$(GLIB_CFLAGS) \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
 	-DLOCALSTATEDIR=\"$(localstatedir)\"
 
 libdns_manager_la_LIBADD = \
diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c
index 8e216f4..e92fecf 100644
--- a/src/dns-manager/nm-dns-dnsmasq.c
+++ b/src/dns-manager/nm-dns-dnsmasq.c
@@ -28,8 +28,10 @@
 
 #include <glib.h>
 #include <glib/gi18n.h>
+#include <dbus/dbus-glib-lowlevel.h>
 
 #include "nm-dns-dnsmasq.h"
+#include "nm-dbus-manager.h"
 #include "nm-logging.h"
 #include "nm-ip4-config.h"
 #include "nm-ip6-config.h"
@@ -42,8 +44,17 @@ G_DEFINE_TYPE (NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
 #define PIDFILE LOCALSTATEDIR "/run/nm-dns-dnsmasq.pid"
 #define CONFFILE LOCALSTATEDIR "/run/nm-dns-dnsmasq.conf"
 
+#define DNSMASQ_SETTINGS_FILE	SYSCONFDIR "/NetworkManager/NetworkManager.conf"
+#define DNSMASQ_SETTINGS_GROUP	"dnsmasq"
+#define DNSMASQ_SETTINGS_USE_DBUS	"use_dbus"
+
+#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
+#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
+
+
 typedef struct {
-	guint32 foo;
+	DBusGProxy	*proxy;
+	gboolean	use_dbus;
 } NMDnsDnsmasqPrivate;
 
 /*******************************************/
@@ -235,6 +246,166 @@ add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split, const char *ifac
 	return TRUE;
 }
 
+static void
+add_ip4_dbus (DBusMessage *msg, NMIP4Config *ip4, gboolean split)
+{
+	int n, i;
+	gboolean added = FALSE;
+	guint32 addr;
+
+	/* FIXME: it appears that dnsmasq can only handle one nameserver
+	 * per domain (and the manpage says this too) so only use the first
+	 * nameserver here.
+	 */
+	addr = htonl(nm_ip4_config_get_nameserver (ip4, 0));
+	dbus_message_append_args(msg, DBUS_TYPE_UINT32, &addr, DBUS_TYPE_INVALID);
+
+	if (split) {
+		char **domains, **iter;
+		const char *ptr;
+
+		/* searches are preferred over domains */
+		n = nm_ip4_config_get_num_searches (ip4);
+		for (i = 0; i < n; i++) {
+			ptr = nm_ip4_config_get_search (ip4, i);
+			dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr, DBUS_TYPE_INVALID);
+			added = TRUE;
+		}
+
+		if (n == 0) {
+			/* If not searches, use any domains */
+			n = nm_ip4_config_get_num_domains (ip4);
+			for (i = 0; i < n; i++) {
+				ptr = nm_ip4_config_get_domain (ip4, i);
+				dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr, DBUS_TYPE_INVALID);
+				added = TRUE;
+			}
+		}
+
+		/* Ensure reverse-DNS works by directing queries for in-addr.arpa
+		 * domains to the split domain's nameserver.
+		 */
+		domains = nm_dns_utils_get_ip4_rdns_domains (ip4);
+		if (domains) {
+			for (iter = domains; iter && *iter; iter++)
+				dbus_message_append_args(msg, DBUS_TYPE_STRING, iter, DBUS_TYPE_INVALID);
+			g_strfreev (domains);
+			added = TRUE;
+		}
+	}
+
+	/* If no searches or domains, just add the rest of the namservers */
+	if (!added) {
+		n = nm_ip4_config_get_num_nameservers (ip4);
+		for (i = 1; i < n; i++) {
+			addr = htonl(nm_ip4_config_get_nameserver (ip4, i));
+			dbus_message_append_args(msg, DBUS_TYPE_UINT32, &addr, DBUS_TYPE_INVALID);
+		}
+	}
+}
+
+static void
+add_ip6_addr (DBusMessage *msg, const struct in6_addr *addr)
+{
+	const unsigned char *p = (const unsigned char *)addr;
+	int i;
+
+	for (i=0; i<sizeof(struct in6_addr); i++)
+		dbus_message_append_args(msg, DBUS_TYPE_BYTE, &p[i], DBUS_TYPE_INVALID);
+}
+
+static void
+add_ip6_dbus (DBusMessage *msg, NMIP6Config *ip6, gboolean split)
+{
+	const struct in6_addr *addr;
+	int n, i;
+	gboolean added = FALSE;
+
+	/* FIXME: it appears that dnsmasq can only handle one nameserver
+	 * per domain (at the manpage seems to indicate that) so only use
+	 * the first nameserver here.
+	 */
+	addr = nm_ip6_config_get_nameserver (ip6, 0);
+	add_ip6_addr (msg, addr);
+
+	if (split) {
+		const char *ptr;
+
+		/* searches are preferred over domains */
+		n = nm_ip6_config_get_num_searches (ip6);
+		for (i = 0; i < n; i++) {
+			ptr = nm_ip6_config_get_search (ip6, i);
+			dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr, DBUS_TYPE_INVALID);
+			added = TRUE;
+		}
+
+		if (n == 0) {
+			/* If not searches, use any domains */
+			n = nm_ip6_config_get_num_domains (ip6);
+			for (i = 0; i < n; i++) {
+	            ptr = nm_ip6_config_get_domain (ip6, i),
+				dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr, DBUS_TYPE_INVALID);
+				added = TRUE;
+			}
+		}
+	}
+
+	/* If no searches or domains, just add the namservers */
+	if (!added) {
+		n = nm_ip6_config_get_num_nameservers (ip6);
+		for (i = 1; i < n; i++) {
+			addr = nm_ip6_config_get_nameserver (ip6, i);
+			add_ip6_addr (msg, addr);
+		}
+	}
+}
+
+static gboolean
+update_dbus (NMDnsPlugin *plugin,
+        const GSList *vpn_configs,
+        const GSList *dev_configs,
+        const GSList *other_configs)
+{
+	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
+	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
+	GSList *iter;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(
+		DNSMASQ_SERVICE,
+		DNSMASQ_PATH,
+		DNSMASQ_SERVICE,
+		"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_dbus (msg, NM_IP4_CONFIG (iter->data), TRUE);
+		else if (NM_IS_IP6_CONFIG (iter->data))
+			add_ip6_dbus (msg, 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_dbus (msg, NM_IP4_CONFIG (iter->data), FALSE);
+		else if (NM_IS_IP6_CONFIG (iter->data))
+			add_ip6_dbus (msg, 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_dbus (msg, NM_IP4_CONFIG (iter->data), FALSE);
+		else if (NM_IS_IP6_CONFIG (iter->data))
+			add_ip6_dbus (msg, NM_IP6_CONFIG (iter->data), FALSE);
+	}
+
+	dbus_g_proxy_send(priv->proxy, msg, NULL);
+	dbus_message_unref(msg);
+	return TRUE;
+}
+
 static gboolean
 update (NMDnsPlugin *plugin,
         const GSList *vpn_configs,
@@ -244,6 +415,7 @@ update (NMDnsPlugin *plugin,
         const char *iface)
 {
 	NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin);
+	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
 	GString *conf;
 	GSList *iter;
 	const char *argv[11];
@@ -251,6 +423,9 @@ update (NMDnsPlugin *plugin,
 	int ignored;
 	GPid pid = 0;
 
+	if (priv->use_dbus) {
+		return update_dbus (plugin, vpn_configs, dev_configs, other_configs);
+	}
 	/* 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
@@ -398,6 +573,42 @@ nm_dns_dnsmasq_new (void)
 static void
 nm_dns_dnsmasq_init (NMDnsDnsmasq *self)
 {
+	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
+	GKeyFile *keyfile;
+	GError *error = NULL;
+
+	priv->use_dbus = FALSE;
+
+	keyfile = g_key_file_new();
+	if (!g_key_file_load_from_file (keyfile,
+	                                DNSMASQ_SETTINGS_FILE,
+	                                G_KEY_FILE_NONE,
+	                                &error)) {
+		nm_log_info (LOGD_SETTINGS, "loading system config file (%s) caused error: (%d) %s",
+		         DNSMASQ_SETTINGS_FILE,
+		         error ? error->code : -1,
+		         error && error->message ? error->message : "(unknown)");
+	} else {
+		priv->use_dbus = g_key_file_get_boolean (keyfile,
+		                                            DNSMASQ_SETTINGS_GROUP,
+		                                            DNSMASQ_SETTINGS_USE_DBUS,
+		                                            &error);
+		if (error) {
+			nm_log_info (LOGD_SETTINGS, "getting keyfile key '%s' in group '%s' failed: (%d) %s",
+			         DNSMASQ_SETTINGS_GROUP,
+			         DNSMASQ_SETTINGS_USE_DBUS,
+			         error ? error->code : -1,
+			         error && error->message ? error->message : "(unknown)");
+		}
+		g_key_file_free (keyfile);
+	}
+	if (priv->use_dbus) {
+		NMDBusManager *dbus_mgr = nm_dbus_manager_get ();
+		priv->proxy = dbus_g_proxy_new_for_name(nm_dbus_manager_get_connection(dbus_mgr),
+			DNSMASQ_SERVICE,
+			DNSMASQ_PATH,
+			DNSMASQ_SERVICE);
+	}
 }
 
 static void
-- 
1.7.5.4



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]