about summary refs log tree commit diff
path: root/src/dns/nm-dns-systemd-resolved.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/nm-dns-systemd-resolved.c')
-rw-r--r--src/dns/nm-dns-systemd-resolved.c289
1 files changed, 159 insertions, 130 deletions
diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c
index 6ab2ea18..7da27e5f 100644
--- a/src/dns/nm-dns-systemd-resolved.c
+++ b/src/dns/nm-dns-systemd-resolved.c
@@ -31,13 +31,15 @@
 #include <sys/stat.h>
 #include <linux/if.h>
 
+#include "nm-utils/nm-c-list.h"
 #include "nm-core-internal.h"
 #include "platform/nm-platform.h"
 #include "nm-utils.h"
 #include "nm-ip4-config.h"
 #include "nm-ip6-config.h"
-#include "nm-bus-manager.h"
+#include "nm-dbus-manager.h"
 #include "nm-manager.h"
+#include "nm-setting-connection.h"
 #include "devices/nm-device.h"
 #include "NetworkManagerUtils.h"
 
@@ -48,17 +50,23 @@
 
 typedef struct {
 	int ifindex;
-	GList *configs;
+	CList configs_lst_head;
 } InterfaceConfig;
 
+typedef struct {
+	CList request_queue_lst;
+	const char *operation;
+	GVariant *argument;
+} RequestItem;
+
 /*****************************************************************************/
 
 typedef struct {
 	GDBusProxy *resolve;
 	GCancellable *init_cancellable;
 	GCancellable *update_cancellable;
-	GQueue dns_updates;
-	GQueue domain_updates;
+	GCancellable *mdns_cancellable;
+	CList request_queue_lst_head;
 } NMDnsSystemdResolvedPrivate;
 
 struct _NMDnsSystemdResolved {
@@ -82,129 +90,95 @@ G_DEFINE_TYPE (NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN
 /*****************************************************************************/
 
 static void
-call_done (GObject *source, GAsyncResult *r, gpointer user_data)
+_request_item_free (RequestItem *request_item)
 {
-	GVariant *v;
-	GError *error = NULL;
-	NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data;
-
-	v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), r, &error);
+	c_list_unlink_stale (&request_item->request_queue_lst);
+	g_variant_unref (request_item->argument);
+	g_slice_free (RequestItem, request_item);
+}
 
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-		return;
+static void
+_request_item_append (CList *request_queue_lst_head,
+                      const char *operation,
+                      GVariant *argument)
+{
+	RequestItem *request_item;
 
-	if (error != NULL) {
-		_LOGW ("Failed: %s\n", error->message);
-		g_error_free (error);
-	}
+	request_item = g_slice_new (RequestItem);
+	request_item->operation = operation;
+	request_item->argument = g_variant_ref_sink (argument);
+	c_list_link_tail (request_queue_lst_head, &request_item->request_queue_lst);
 }
 
+/*****************************************************************************/
+
 static void
-add_interface_configuration (NMDnsSystemdResolved *self,
-                             GArray *interfaces,
-                             const NMDnsIPConfigData *data,
-                             gboolean skip)
+_interface_config_free (InterfaceConfig *config)
 {
-	int i;
-	InterfaceConfig *ic = NULL;
-	int ifindex;
+	nm_c_list_elem_free_all (&config->configs_lst_head, NULL);
+	g_slice_free (InterfaceConfig, config);
+}
 
-	if (NM_IS_IP4_CONFIG (data->config))
-		ifindex = nm_ip4_config_get_ifindex (data->config);
-	else if (NM_IS_IP6_CONFIG  (data->config))
-		ifindex = nm_ip6_config_get_ifindex (data->config);
-	else
-		g_return_if_reached ();
-
-	for (i = 0; i < interfaces->len; i++) {
-		InterfaceConfig *tic = &g_array_index (interfaces, InterfaceConfig, i);
-		if (ifindex == tic->ifindex) {
-			ic = tic;
-			break;
-		}
-	}
+static void
+call_done (GObject *source, GAsyncResult *r, gpointer user_data)
+{
+	GVariant *v;
+	GError *error = NULL;
+	NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data;
 
-	if (!ic) {
-		g_array_set_size (interfaces, interfaces->len + 1);
-		ic = &g_array_index (interfaces, InterfaceConfig,
-		                     interfaces->len - 1);
-		ic->ifindex = ifindex;
+	v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), r, &error);
+	if (!v) {
+		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			return;
+		_LOGW ("Failed: %s\n", error->message);
+		g_error_free (error);
 	}
-
-	if (!skip)
-		ic->configs = g_list_append (ic->configs, data->config);
 }
 
 static void
 update_add_ip_config (NMDnsSystemdResolved *self,
                       GVariantBuilder *dns,
                       GVariantBuilder *domains,
-                      gpointer config)
+                      NMIPConfig *config)
 {
 	int addr_family;
 	gsize addr_size;
 	guint i, n;
-	gboolean route_only;
-
-	if (NM_IS_IP4_CONFIG (config))
-		addr_family = AF_INET;
-	else if (NM_IS_IP6_CONFIG (config))
-		addr_family = AF_INET6;
-	else
-		g_return_if_reached ();
+	gboolean is_routing;
+	const char *domain;
 
+	addr_family = nm_ip_config_get_addr_family (config);
 	addr_size = nm_utils_addr_family_to_size (addr_family);
 
-	n =   addr_family == AF_INET
-	    ? nm_ip4_config_get_num_nameservers (config)
-	    : nm_ip6_config_get_num_nameservers (config);
+	n = nm_ip_config_get_num_nameservers (config);
 	for (i = 0 ; i < n; i++) {
-		in_addr_t ns4;
-		gconstpointer ns;
-
-		if (addr_family == AF_INET) {
-			ns4 = nm_ip4_config_get_nameserver (config, i);
-			ns = &ns4;
-		} else
-			ns = nm_ip6_config_get_nameserver (config, i);
-
 		g_variant_builder_open (dns, G_VARIANT_TYPE ("(iay)"));
 		g_variant_builder_add (dns, "i", addr_family);
 		g_variant_builder_add_value (dns,
 		                             g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
-		                                                        ns,
+		                                                        nm_ip_config_get_nameserver (config, i),
 		                                                        addr_size,
 		                                                        1));
 		g_variant_builder_close (dns);
 	}
 
-	/* If this link is never the default (e.g. only used for resources on this
-	 * network) add a routing domain. */
-	route_only =   addr_family == AF_INET
-	             ? !nm_ip4_config_best_default_route_get (config)
-	             : !nm_ip6_config_best_default_route_get (config);
-
-	n =   addr_family == AF_INET
-	    ? nm_ip4_config_get_num_searches (config)
-	    : nm_ip6_config_get_num_searches (config);
+	n = nm_ip_config_get_num_searches (config);
 	if (n  > 0) {
 		for (i = 0; i < n; i++) {
+			domain = nm_utils_parse_dns_domain (nm_ip_config_get_search (config, i),
+			                                    &is_routing);
 			g_variant_builder_add (domains, "(sb)",
-			                       addr_family == AF_INET
-			                         ? nm_ip4_config_get_search (config, i)
-			                         : nm_ip6_config_get_search (config, i),
-			                       route_only);
+			                       domain,
+			                       is_routing);
 		}
 	} else {
-		n =   addr_family == AF_INET
-		    ? nm_ip4_config_get_num_domains (config)
-		    : nm_ip6_config_get_num_domains (config);
+		n = nm_ip_config_get_num_domains (config);
 		for (i = 0; i < n; i++) {
+			domain = nm_utils_parse_dns_domain (nm_ip_config_get_domain (config, i),
+			                                    &is_routing);
 			g_variant_builder_add (domains, "(sb)",
-			                       addr_family == AF_INET
-			                         ? nm_ip4_config_get_domain (config, i)
-			                         : nm_ip6_config_get_domain (config, i),
-			                       route_only);
+			                       domain,
+			                       is_routing);
 		}
 	}
 }
@@ -213,13 +187,13 @@ static void
 free_pending_updates (NMDnsSystemdResolved *self)
 {
 	NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self);
-	GVariant *v;
+	RequestItem *request_item, *request_item_safe;
 
-	while ((v = g_queue_pop_head (&priv->dns_updates)) != NULL)
-		g_variant_unref (v);
-
-	while ((v = g_queue_pop_head (&priv->domain_updates)) != NULL)
-		g_variant_unref (v);
+	c_list_for_each_entry_safe (request_item,
+	                            request_item_safe,
+	                            &priv->request_queue_lst_head,
+	                            request_queue_lst)
+		_request_item_free (request_item);
 }
 
 static void
@@ -227,7 +201,9 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic)
 {
 	NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self);
 	GVariantBuilder dns, domains;
-	GList *l;
+	NMCListElem *elem;
+	NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
+	const char *mdns_arg = NULL;
 
 	g_variant_builder_init (&dns, G_VARIANT_TYPE ("(ia(iay))"));
 	g_variant_builder_add (&dns, "i", ic->ifindex);
@@ -237,23 +213,50 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic)
 	g_variant_builder_add (&domains, "i", ic->ifindex);
 	g_variant_builder_open (&domains, G_VARIANT_TYPE ("a(sb)"));
 
-	for (l = ic->configs; l; l = l->next)
-		update_add_ip_config (self, &dns, &domains, l->data);
+	c_list_for_each_entry (elem, &ic->configs_lst_head, lst) {
+		NMIPConfig *ip_config = elem->data;
+
+		update_add_ip_config (self, &dns, &domains, ip_config);
+
+		if (NM_IS_IP4_CONFIG (ip_config))
+			mdns = NM_MAX (mdns, nm_ip4_config_mdns_get (NM_IP4_CONFIG (ip_config)));
+	}
 
 	g_variant_builder_close (&dns);
 	g_variant_builder_close (&domains);
 
-	g_queue_push_tail (&priv->dns_updates,
-	                   g_variant_ref_sink (g_variant_builder_end (&dns)));
-	g_queue_push_tail (&priv->domain_updates,
-	                   g_variant_ref_sink (g_variant_builder_end (&domains)));
+	switch (mdns) {
+	case NM_SETTING_CONNECTION_MDNS_NO:
+		mdns_arg = "no";
+		break;
+	case NM_SETTING_CONNECTION_MDNS_RESOLVE:
+		mdns_arg = "resolve";
+		break;
+	case NM_SETTING_CONNECTION_MDNS_YES:
+		mdns_arg = "yes";
+		break;
+	case NM_SETTING_CONNECTION_MDNS_DEFAULT:
+		mdns_arg = "";
+		break;
+	}
+	nm_assert (mdns_arg);
+
+	_request_item_append (&priv->request_queue_lst_head,
+	                      "SetLinkDNS",
+	                      g_variant_builder_end (&dns));
+	_request_item_append (&priv->request_queue_lst_head,
+	                      "SetLinkDomains",
+	                      g_variant_builder_end (&domains));
+	_request_item_append (&priv->request_queue_lst_head,
+	                      "SetLinkMulticastDNS",
+	                      g_variant_new ("(is)", ic->ifindex, mdns_arg ?: ""));
 }
 
 static void
 send_updates (NMDnsSystemdResolved *self)
 {
 	NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self);
-	GVariant *v;
+	RequestItem *request_item, *request_item_safe;
 
 	nm_clear_g_cancellable (&priv->update_cancellable);
 
@@ -262,55 +265,81 @@ send_updates (NMDnsSystemdResolved *self)
 
 	priv->update_cancellable = g_cancellable_new ();
 
-	while ((v = g_queue_pop_head (&priv->dns_updates)) != NULL) {
-		g_dbus_proxy_call (priv->resolve, "SetLinkDNS", v,
+	c_list_for_each_entry_safe (request_item,
+	                            request_item_safe,
+	                            &priv->request_queue_lst_head,
+	                            request_queue_lst) {
+		g_dbus_proxy_call (priv->resolve,
+		                   request_item->operation,
+		                   request_item->argument,
 		                   G_DBUS_CALL_FLAGS_NONE,
-		                   -1, priv->update_cancellable, call_done, self);
-		g_variant_unref (v);
-	}
-
-	while ((v = g_queue_pop_head (&priv->domain_updates)) != NULL) {
-		g_dbus_proxy_call (priv->resolve, "SetLinkDomains", v,
-		                   G_DBUS_CALL_FLAGS_NONE,
-		                   -1, priv->update_cancellable, call_done, self);
-		g_variant_unref (v);
+		                   -1,
+		                   priv->update_cancellable,
+		                   call_done,
+		                   self);
+		_request_item_free (request_item);
 	}
 }
 
 static gboolean
 update (NMDnsPlugin *plugin,
-        const GPtrArray *configs,
         const NMGlobalDnsConfig *global_config,
+        const CList *ip_config_lst_head,
         const char *hostname)
 {
 	NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED (plugin);
-	GArray *interfaces = g_array_new (TRUE, TRUE, sizeof (InterfaceConfig));
+	gs_unref_hashtable GHashTable *interfaces = NULL;
+	gs_free gpointer *interfaces_keys = NULL;
+	guint interfaces_len;
 	guint i;
 	int prio, first_prio = 0;
+	NMDnsIPConfigData *ip_data;
+	gboolean is_first = TRUE;
+
+	interfaces = g_hash_table_new_full (nm_direct_hash, NULL,
+	                                    NULL, (GDestroyNotify) _interface_config_free);
 
-	for (i = 0; i < configs->len; i++) {
-		const NMDnsIPConfigData *data = configs->pdata[i];
+	c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) {
 		gboolean skip = FALSE;
+		InterfaceConfig *ic = NULL;
+		int ifindex;
 
-		prio = nm_ip_config_get_dns_priority (data->config);
-		if (i == 0)
+		prio = nm_ip_config_get_dns_priority (ip_data->ip_config);
+		if (is_first) {
+			is_first = FALSE;
 			first_prio = prio;
-		else if (first_prio < 0 && first_prio != prio)
+		} else if (first_prio < 0 && first_prio != prio)
 			skip = TRUE;
-		add_interface_configuration (self, interfaces, data, skip);
+
+		ifindex = ip_data->data->ifindex;
+		nm_assert (ifindex == nm_ip_config_get_ifindex (ip_data->ip_config));
+
+		ic = g_hash_table_lookup (interfaces, GINT_TO_POINTER (ifindex));
+		if (!ic) {
+			ic = g_slice_new (InterfaceConfig);
+			ic->ifindex = ifindex;
+			c_list_init (&ic->configs_lst_head);
+			g_hash_table_insert (interfaces, GINT_TO_POINTER (ifindex), ic);
+		}
+
+		if (!skip) {
+			c_list_link_tail (&ic->configs_lst_head,
+			                  &nm_c_list_elem_new_stale (ip_data->ip_config)->lst);
+		}
 	}
 
 	free_pending_updates (self);
 
-	for (i = 0; i < interfaces->len; i++) {
-		InterfaceConfig *ic = &g_array_index (interfaces, InterfaceConfig, i);
+	interfaces_keys = nm_utils_hash_keys_to_array (interfaces,
+	                                               nm_cmp_int2ptr_p_with_data,
+	                                               NULL,
+	                                               &interfaces_len);
+	for (i = 0; i < interfaces_len; i++) {
+		InterfaceConfig *ic = g_hash_table_lookup (interfaces, GINT_TO_POINTER (interfaces_keys[i]));
 
 		prepare_one_interface (self, ic);
-		g_list_free (ic->configs);
 	}
 
-	g_array_free (interfaces, TRUE);
-
 	send_updates (self);
 
 	return TRUE;
@@ -363,16 +392,15 @@ static void
 nm_dns_systemd_resolved_init (NMDnsSystemdResolved *self)
 {
 	NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self);
-	NMBusManager *dbus_mgr;
+	NMDBusManager *dbus_mgr;
 	GDBusConnection *connection;
 
-	g_queue_init (&priv->dns_updates);
-	g_queue_init (&priv->domain_updates);
+	c_list_init (&priv->request_queue_lst_head);
 
-	dbus_mgr = nm_bus_manager_get ();
+	dbus_mgr = nm_dbus_manager_get ();
 	g_return_if_fail (dbus_mgr);
 
-	connection = nm_bus_manager_get_connection (dbus_mgr);
+	connection = nm_dbus_manager_get_connection (dbus_mgr);
 	g_return_if_fail (connection);
 
 	priv->init_cancellable = g_cancellable_new ();
@@ -404,6 +432,7 @@ dispose (GObject *object)
 	g_clear_object (&priv->resolve);
 	nm_clear_g_cancellable (&priv->init_cancellable);
 	nm_clear_g_cancellable (&priv->update_cancellable);
+	nm_clear_g_cancellable (&priv->mdns_cancellable);
 
 	G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object);
 }