summary refs log tree commit diff
path: root/src/dns/nm-dns-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/nm-dns-manager.c')
-rw-r--r--src/dns/nm-dns-manager.c210
1 files changed, 126 insertions, 84 deletions
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c
index d731e7bf..b40dd6b6 100644
--- a/src/dns/nm-dns-manager.c
+++ b/src/dns/nm-dns-manager.c
@@ -178,7 +178,8 @@ domain_is_routing (const char *domain)
 
 /*****************************************************************************/
 
-NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConfManager,
+static
+NM_UTILS_LOOKUP_STR_DEFINE (_rc_manager_to_string, NMDnsManagerResolvConfManager,
 	NM_UTILS_LOOKUP_DEFAULT_WARN (NULL),
 	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN,        "unknown"),
 	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,      "unmanaged"),
@@ -189,7 +190,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConf
 	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG,      "netconfig"),
 );
 
-NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_config_type_to_string, NMDnsIPConfigType,
+static
+NM_UTILS_LOOKUP_STR_DEFINE (_config_type_to_string, NMDnsIPConfigType,
 	NM_UTILS_LOOKUP_DEFAULT_WARN ("<unknown>"),
 	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_REMOVED, "removed"),
 	NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_DEFAULT, "default"),
@@ -425,9 +427,9 @@ merge_one_ip_config (NMResolvConfData *rc,
 		if (addr_family == AF_INET)
 			nm_utils_inet_ntop (addr_family, addr, buf);
 		else if (IN6_IS_ADDR_V4MAPPED (addr))
-			nm_utils_inet4_ntop (addr->addr6.s6_addr32[3], buf);
+			_nm_utils_inet4_ntop (addr->addr6.s6_addr32[3], buf);
 		else {
-			nm_utils_inet6_ntop (&addr->addr6, buf);
+			_nm_utils_inet6_ntop (&addr->addr6, buf);
 			if (IN6_IS_ADDR_LINKLOCAL (addr)) {
 				const char *ifname;
 
@@ -457,7 +459,7 @@ merge_one_ip_config (NMResolvConfData *rc,
 		num = nm_ip4_config_get_num_nis_servers (ip4_config);
 		for (i = 0; i < num; i++) {
 			add_string_item (rc->nis_servers,
-			                 nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (ip4_config, i), buf),
+			                 _nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (ip4_config, i), buf),
 			                 TRUE);
 		}
 
@@ -858,9 +860,11 @@ update_resolv_conf (NMDnsManager *self,
 		if (!g_file_set_contents (rc_path, content, -1, &local)) {
 			_LOGT ("update-resolv-conf: write to %s failed (rc-manager=%s, %s)",
 			       rc_path, _rc_manager_to_string (rc_manager), local->message);
-			write_file_result = SR_ERROR;
 			g_propagate_error (error, local);
+			/* clear @error, so that we don't try reset it. This is the error
+			 * we want to propagate to the caller. */
 			error = NULL;
+			write_file_result = SR_ERROR;
 		} else {
 			_LOGT ("update-resolv-conf: write to %s succeeded (rc-manager=%s)",
 			       rc_path, _rc_manager_to_string (rc_manager));
@@ -928,7 +932,7 @@ update_resolv_conf (NMDnsManager *self,
 	if (   rc_manager != NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK
 	    || !_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link)) {
 		_LOGT ("update-resolv-conf: write internal file %s succeeded", MY_RESOLV_CONF);
-		return SR_SUCCESS;
+		return write_file_result;
 	}
 
 	if (!nm_streq0 (_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link),
@@ -936,7 +940,7 @@ update_resolv_conf (NMDnsManager *self,
 		_LOGT ("update-resolv-conf: write internal file %s succeeded (don't touch symlink %s linking to %s)",
 		       MY_RESOLV_CONF, _PATH_RESCONF,
 		       _read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link));
-		return SR_SUCCESS;
+		return write_file_result;
 	}
 
 	/* By this point, /etc/resolv.conf exists and is a symlink to our internal
@@ -989,7 +993,7 @@ update_resolv_conf (NMDnsManager *self,
 
 	_LOGT ("update-resolv-conf: write internal file %s succeeded and update symlink %s",
 	       MY_RESOLV_CONF, _PATH_RESCONF);
-	return SR_SUCCESS;
+	return write_file_result;
 }
 
 static void
@@ -1161,7 +1165,7 @@ _collect_resolv_conf_data (NMDnsManager *self,
 		const char *hostdomain = strchr (priv->hostname, '.');
 
 		if (   hostdomain
-		    && !nm_utils_ipaddr_valid (AF_UNSPEC, priv->hostname)) {
+		    && !nm_utils_ipaddr_is_valid (AF_UNSPEC, priv->hostname)) {
 			hostdomain++;
 			if (domain_is_valid (hostdomain, TRUE))
 				add_string_item (rc.searches, hostdomain, TRUE);
@@ -1227,26 +1231,34 @@ get_ip_rdns_domains (NMIPConfig *ip_config)
 /* Check if the domain is shadowed by a parent domain with more negative priority */
 static gboolean
 domain_is_shadowed (GHashTable *ht,
-                    const char *domain, int priority,
-                    const char **out_parent, int *out_parent_priority)
+                    const char *domain,
+                    int priority,
+                    const char **out_parent,
+                    int *out_parent_priority)
 {
 	char *parent;
 	int parent_priority;
 
+	if (!ht)
+		return FALSE;
+
 	nm_assert (!g_hash_table_contains (ht, domain));
 
 	parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, ""));
-	if (parent_priority < 0 && parent_priority < priority) {
+	if (   parent_priority < 0
+	    && parent_priority < priority) {
 		*out_parent = "";
 		*out_parent_priority = parent_priority;
 		return TRUE;
 	}
 
 	parent = strchr (domain, '.');
-	while (parent && parent[1]) {
+	while (   parent
+	       && parent[1]) {
 		parent++;
 		parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, parent));
-		if (parent_priority < 0 && parent_priority < priority) {
+		if (   parent_priority < 0
+		    && parent_priority < priority) {
 			*out_parent = parent;
 			*out_parent_priority = parent_priority;
 			return TRUE;
@@ -1265,8 +1277,6 @@ rebuild_domain_lists (NMDnsManager *self)
 	gboolean default_route_found = FALSE;
 	CList *head;
 
-	ht = g_hash_table_new (nm_str_hash, g_str_equal);
-
 	head = _ip_config_lst_head (self);
 	c_list_for_each_entry (ip_data, head, ip_config_lst) {
 		NMIPConfig *ip_config = ip_data->ip_config;
@@ -1281,55 +1291,71 @@ rebuild_domain_lists (NMDnsManager *self)
 
 	c_list_for_each_entry (ip_data, head, ip_config_lst) {
 		NMIPConfig *ip_config = ip_data->ip_config;
-		int priority, old_priority;
-		guint i, n, n_domains = 0;
+		int priority;
 		const char **domains;
+		guint n_searches;
+		guint n_domains;
+		guint num_dom1;
+		guint num_dom2;
+		guint cap_dom;
+		guint i;
 
 		if (!nm_ip_config_get_num_nameservers (ip_config))
 			continue;
 
+		n_searches = nm_ip_config_get_num_searches (ip_config);
+		n_domains = nm_ip_config_get_num_domains (ip_config);
+
 		priority = nm_ip_config_get_dns_priority (ip_config);
 		nm_assert (priority != 0);
+
+		cap_dom = 2u + NM_MAX (n_domains, n_searches);
+
 		g_free (ip_data->domains.search);
-		domains = g_new0 (const char *,
-		                  2 + NM_MAX (nm_ip_config_get_num_searches (ip_config),
-		                              nm_ip_config_get_num_domains (ip_config)));
+		domains = g_new (const char *, cap_dom);
 		ip_data->domains.search = domains;
 
+		num_dom1 = 0;
+
 		/* Add wildcard lookup domain to connections with the default route.
 		 * If there is no default route, add the wildcard domain to all non-VPN
 		 * connections */
 		if (default_route_found) {
+			/* FIXME: this heuristic of which device has a default route does
+			 * not work with policy routing (as used by default with WireGuard).
+			 * We should have a more stable mechanism where an NMIPConfig indicates
+			 * whether it is suitable for certain operations (like having an automatically
+			 * added "~" domain). */
 			if (nm_ip_config_best_default_route_get (ip_config))
-				domains[n_domains++] = "~";
+				domains[num_dom1++] = "~";
 		} else {
 			if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN)
-				domains[n_domains++] = "~";
+				domains[num_dom1++] = "~";
 		}
 
 		/* searches are preferred over domains */
-		n = nm_ip_config_get_num_searches (ip_config);
-		for (i = 0; i < n; i++)
-			domains[n_domains++] = nm_ip_config_get_search (ip_config, i);
-
-		if (n == 0) {
-			/* If not searches, use any domains */
-			n = nm_ip_config_get_num_domains (ip_config);
-			for (i = 0; i < n; i++)
-				domains[n_domains++] = nm_ip_config_get_domain (ip_config, i);
+		if (n_searches > 0) {
+			for (i = 0; i < n_searches; i++)
+				domains[num_dom1++] = nm_ip_config_get_search (ip_config, i);
+		} else {
+			for (i = 0; i < n_domains; i++)
+				domains[num_dom1++] = nm_ip_config_get_domain (ip_config, i);
 		}
 
-		n = 0;
-		for (i = 0; i < n_domains; i++) {
+		nm_assert (num_dom1 < cap_dom);
+
+		num_dom2 = 0;
+		for (i = 0; i < num_dom1; i++) {
 			const char *domain_clean;
 			const char *parent;
+			int old_priority;
 			int parent_priority;
 
 			domain_clean = nm_utils_parse_dns_domain (domains[i], NULL);
 
 			/* Remove domains with lower priority */
-			old_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, domain_clean));
-			if (old_priority) {
+			old_priority = GPOINTER_TO_INT (nm_g_hash_table_lookup (ht, domain_clean));
+			if (old_priority != 0) {
 				if (old_priority < priority) {
 					_LOGT ("plugin: drop domain '%s' (i=%d, p=%d) because it already exists with p=%d",
 					       domains[i], ip_data->data->ifindex,
@@ -1345,10 +1371,13 @@ rebuild_domain_lists (NMDnsManager *self)
 			}
 
 			_LOGT ("plugin: add domain '%s' (i=%d, p=%d)", domains[i], ip_data->data->ifindex, priority);
+			if (!ht)
+				ht = g_hash_table_new (nm_str_hash, g_str_equal);
 			g_hash_table_insert (ht, (gpointer) domain_clean, GINT_TO_POINTER (priority));
-			domains[n++] = domains[i];
+			domains[num_dom2++] = domains[i];
 		}
-		domains[n] = NULL;
+		nm_assert (num_dom2 < cap_dom);
+		domains[num_dom2] = NULL;
 
 		g_strfreev (ip_data->domains.reverse);
 		ip_data->domains.reverse = get_ip_rdns_domains (ip_config);
@@ -1363,8 +1392,8 @@ clear_domain_lists (NMDnsManager *self)
 
 	head = _ip_config_lst_head (self);
 	c_list_for_each_entry (ip_data, head, ip_config_lst) {
-		g_clear_pointer (&ip_data->domains.search, g_free);
-		g_clear_pointer (&ip_data->domains.reverse, g_strfreev);
+		nm_clear_g_free (&ip_data->domains.search);
+		nm_clear_pointer (&ip_data->domains.reverse, g_strfreev);
 	}
 }
 
@@ -1373,21 +1402,24 @@ update_dns (NMDnsManager *self,
             gboolean no_caching,
             GError **error)
 {
-	NMDnsManagerPrivate *priv;
+	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 	const char *nis_domain = NULL;
 	gs_strfreev char **searches = NULL;
 	gs_strfreev char **options = NULL;
 	gs_strfreev char **nameservers = NULL;
 	gs_strfreev char **nis_servers = NULL;
-	gboolean caching = FALSE, update = TRUE;
+	gboolean caching = FALSE;
+	gboolean do_update = TRUE;
 	gboolean resolv_conf_updated = FALSE;
-	SpawnResult result = SR_ERROR;
+	SpawnResult result = SR_SUCCESS;
 	NMConfigData *data;
 	NMGlobalDnsConfig *global_config;
+	gs_free_error GError *local_error = NULL;
+	GError **const p_local_error =   error
+	                               ? &local_error
+	                               : NULL;
 
-	g_return_val_if_fail (!error || !*error, FALSE);
-
-	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
+	nm_assert (!error || !*error);
 
 	if (priv->is_stopped) {
 		_LOGD ("update-dns: not updating resolv.conf (is stopped)");
@@ -1398,7 +1430,7 @@ update_dns (NMDnsManager *self,
 
 	if (NM_IN_SET (priv->rc_manager, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED,
 	                                 NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE)) {
-		update = FALSE;
+		do_update = FALSE;
 		_LOGD ("update-dns: not updating resolv.conf");
 	} else {
 		priv->dns_touched = TRUE;
@@ -1436,7 +1468,7 @@ update_dns (NMDnsManager *self,
 			if (no_caching) {
 				_LOGD ("update-dns: plugin %s ignored (caching disabled)",
 				       plugin_name);
-				goto skip;
+				goto plugin_skip;
 			}
 			caching = TRUE;
 		}
@@ -1455,7 +1487,7 @@ update_dns (NMDnsManager *self,
 			caching = FALSE;
 		}
 
-	skip:
+plugin_skip:
 		;
 	}
 
@@ -1486,7 +1518,7 @@ update_dns (NMDnsManager *self,
 		nameservers[0] = g_strdup (lladdr);
 	}
 
-	if (update) {
+	if (do_update) {
 		switch (priv->rc_manager) {
 		case NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK:
 		case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE:
@@ -1494,7 +1526,7 @@ update_dns (NMDnsManager *self,
 			                             NM_CAST_STRV_CC (searches),
 			                             NM_CAST_STRV_CC (nameservers),
 			                             NM_CAST_STRV_CC (options),
-			                             error,
+			                             p_local_error,
 			                             priv->rc_manager);
 			resolv_conf_updated = TRUE;
 			/* If we have ended with no nameservers avoid updating again resolv.conf
@@ -1503,7 +1535,11 @@ update_dns (NMDnsManager *self,
 				priv->dns_touched = FALSE;
 			break;
 		case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF:
-			result = dispatch_resolvconf (self, searches, nameservers, options, error);
+			result = dispatch_resolvconf (self,
+			                              searches,
+			                              nameservers,
+			                              options,
+			                              p_local_error);
 			break;
 		case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG:
 			result = dispatch_netconfig (self,
@@ -1511,20 +1547,20 @@ update_dns (NMDnsManager *self,
 			                             (const char *const*) nameservers,
 			                             nis_domain,
 			                             (const char *const*) nis_servers,
-			                             error);
+			                             p_local_error);
 			break;
 		default:
-			g_assert_not_reached ();
+			nm_assert_not_reached ();
 		}
 
 		if (result == SR_NOTFOUND) {
 			_LOGD ("update-dns: program not available, writing to resolv.conf");
-			g_clear_error (error);
+			g_clear_error (&local_error);
 			result = update_resolv_conf (self,
 			                             NM_CAST_STRV_CC (searches),
 			                             NM_CAST_STRV_CC (nameservers),
 			                             NM_CAST_STRV_CC (options),
-			                             error,
+			                             p_local_error,
 			                             NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK);
 			resolv_conf_updated = TRUE;
 		}
@@ -1542,13 +1578,21 @@ update_dns (NMDnsManager *self,
 	}
 
 	/* signal that resolv.conf was changed */
-	if (update && result == SR_SUCCESS)
+	if (   do_update
+	    && result == SR_SUCCESS)
 		g_signal_emit (self, signals[CONFIG_CHANGED], 0);
 
-	g_clear_pointer (&priv->config_variant, g_variant_unref);
+	nm_clear_pointer (&priv->config_variant, g_variant_unref);
 	_notify (self, PROP_CONFIGURATION);
 
-	return !update || result == SR_SUCCESS;
+	if (result != SR_SUCCESS) {
+		if (error)
+			g_propagate_error (error, g_steal_pointer (&local_error));
+		return FALSE;
+	}
+
+	nm_assert (!local_error);
+	return TRUE;
 }
 
 /*****************************************************************************/
@@ -1569,7 +1613,6 @@ nm_dns_manager_set_ip_config (NMDnsManager *self,
                               NMDnsIPConfigType ip_config_type)
 {
 	NMDnsManagerPrivate *priv;
-	GError *error = NULL;
 	NMDnsIPConfigData *ip_data;
 	NMDnsConfigData *data;
 	int ifindex;
@@ -1642,10 +1685,11 @@ nm_dns_manager_set_ip_config (NMDnsManager *self,
 	}
 
 changed:
-	if (   !priv->updates_queue
-	    && !update_dns (self, FALSE, &error)) {
-		_LOGW ("could not commit DNS changes: %s", error->message);
-		g_clear_error (&error);
+	if (!priv->updates_queue) {
+		gs_free_error GError *error = NULL;
+
+		if (!update_dns (self, FALSE, &error))
+			_LOGW ("could not commit DNS changes: %s", error->message);
 	}
 
 	return TRUE;
@@ -1667,7 +1711,6 @@ nm_dns_manager_set_hostname (NMDnsManager *self,
                              gboolean skip_update)
 {
 	NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
-	GError *error = NULL;
 	const char *filtered = NULL;
 
 	/* Certain hostnames we don't want to include in resolv.conf 'searches' */
@@ -1687,9 +1730,12 @@ nm_dns_manager_set_hostname (NMDnsManager *self,
 
 	if (skip_update)
 		return;
-	if (!priv->updates_queue && !update_dns (self, FALSE, &error)) {
-		_LOGW ("could not commit DNS changes: %s", error->message);
-		g_clear_error (&error);
+
+	if (!priv->updates_queue) {
+		gs_free_error GError *error = NULL;
+
+		if (!update_dns (self, FALSE, &error))
+			_LOGW ("could not commit DNS changes: %s", error->message);
 	}
 }
 
@@ -1714,7 +1760,7 @@ void
 nm_dns_manager_end_updates (NMDnsManager *self, const char *func)
 {
 	NMDnsManagerPrivate *priv;
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 	gboolean changed;
 	guint8 new[HASH_LEN];
 
@@ -1735,10 +1781,8 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func)
 
 	/* Commit all the outstanding changes */
 	_LOGD ("(%s): committing DNS changes (%d)", func, priv->updates_queue);
-	if (!update_dns (self, FALSE, &error)) {
+	if (!update_dns (self, FALSE, &error))
 		_LOGW ("could not commit DNS changes: %s", error->message);
-		g_clear_error (&error);
-	}
 
 	memset (priv->prev_hash, 0, sizeof (priv->prev_hash));
 }
@@ -1747,7 +1791,6 @@ void
 nm_dns_manager_stop (NMDnsManager *self)
 {
 	NMDnsManagerPrivate *priv;
-	GError *error = NULL;
 
 	priv = NM_DNS_MANAGER_GET_PRIVATE (self);
 
@@ -1764,10 +1807,11 @@ nm_dns_manager_stop (NMDnsManager *self)
 	if (   priv->dns_touched
 	    && priv->plugin
 	    && NM_IS_DNS_DNSMASQ (priv->plugin)) {
-		if (!update_dns (self, TRUE, &error)) {
+		gs_free_error GError *error = NULL;
+
+		if (!update_dns (self, TRUE, &error))
 			_LOGW ("could not commit DNS changes on shutdown: %s", error->message);
-			g_clear_error (&error);
-		}
+
 		priv->dns_touched = FALSE;
 	}
 
@@ -2041,8 +2085,6 @@ config_changed_cb (NMConfig *config,
                    NMConfigData *old_data,
                    NMDnsManager *self)
 {
-	GError *error = NULL;
-
 	if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_DNS_MODE |
 	                           NM_CONFIG_CHANGE_RC_MANAGER |
 	                           NM_CONFIG_CHANGE_CAUSE_SIGHUP |
@@ -2063,10 +2105,10 @@ config_changed_cb (NMConfig *config,
 	                           NM_CONFIG_CHANGE_DNS_MODE |
 	                           NM_CONFIG_CHANGE_RC_MANAGER |
 	                           NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) {
-		if (!update_dns (self, FALSE, &error)) {
+		gs_free_error GError *error = NULL;
+
+		if (!update_dns (self, FALSE, &error))
 			_LOGW ("could not commit DNS changes: %s", error->message);
-			g_clear_error (&error);
-		}
 	}
 }
 
@@ -2296,7 +2338,7 @@ dispose (GObject *object)
 	c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_config_lst_head, ip_config_lst)
 		_ip_config_data_free (ip_data);
 
-	g_clear_pointer (&priv->configs, g_hash_table_destroy);
+	nm_clear_pointer (&priv->configs, g_hash_table_destroy);
 
 	nm_clear_g_source (&priv->plugin_ratelimit.timer);
 
@@ -2304,7 +2346,7 @@ dispose (GObject *object)
 
 	G_OBJECT_CLASS (nm_dns_manager_parent_class)->dispose (object);
 
-	g_clear_pointer (&priv->config_variant, g_variant_unref);
+	nm_clear_pointer (&priv->config_variant, g_variant_unref);
 }
 
 static void