summary refs log tree commit diff
path: root/src/dns/nm-dns-manager.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
committerMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
commit964ae8cc391520440cf5aa13e2b9cc34850ea6c2 (patch)
tree50da9ecaee7fbb612ec18f9e24f7dec215bf7861 /src/dns/nm-dns-manager.c
parent3626b425d1bc017fdc6f1ea0cfd329d1e1681641 (diff)
New upstream version 1.14.6 upstream/1.14.6
Diffstat (limited to 'src/dns/nm-dns-manager.c')
-rw-r--r--src/dns/nm-dns-manager.c163
1 files changed, 101 insertions, 62 deletions
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c
index 6a59b41c..aebe3e12 100644
--- a/src/dns/nm-dns-manager.c
+++ b/src/dns/nm-dns-manager.c
@@ -55,7 +55,7 @@
 #include "nm-dns-systemd-resolved.h"
 #include "nm-dns-unbound.h"
 
-#define HASH_LEN 20
+#define HASH_LEN   NM_UTILS_CHECKSUM_LENGTH_SHA1
 
 #ifndef RESOLVCONF_PATH
 #define RESOLVCONF_PATH "/sbin/resolvconf"
@@ -582,53 +582,85 @@ again:
 }
 
 static char *
-create_resolv_conf (char **searches,
-                    char **nameservers,
-                    char **options)
+create_resolv_conf (const char *const*searches,
+                    const char *const*nameservers,
+                    const char *const*options)
 {
-	gs_free char *searches_str = NULL;
-	gs_free char *nameservers_str = NULL;
-	gs_free char *options_str = NULL;
-	char *tmp_str;
 	GString *str;
-	int i;
+	gsize i;
 
-	if (searches) {
-		tmp_str = g_strjoinv (" ", searches);
-		searches_str = g_strconcat ("search ", tmp_str, "\n", NULL);
-		g_free (tmp_str);
-	}
+	str = g_string_new_len (NULL, 245);
 
-	if (options) {
-		tmp_str = g_strjoinv (" ", options);
-		options_str = g_strconcat ("options ", tmp_str, "\n", NULL);
-		g_free (tmp_str);
-	}
+	g_string_append (str, "# Generated by NetworkManager\n");
 
-	if (nameservers) {
-		int num = g_strv_length (nameservers);
+	if (searches && searches[0]) {
+		gsize search_base_idx;
 
-		str = g_string_new ("");
-		for (i = 0; i < num; i++) {
-			if (i == 3) {
-				g_string_append (str, "# ");
-				g_string_append (str, "NOTE: the libc resolver may not support more than 3 nameservers.");
-				g_string_append (str, "\n# ");
-				g_string_append (str, "The nameservers listed below may not be recognized.");
-				g_string_append_c (str, '\n');
+		g_string_append (str, "search");
+		search_base_idx = str->len;
+
+		for (i = 0; searches[i]; i++) {
+			const char *s = searches[i];
+			gsize l = strlen (s);
+
+			if (   l == 0
+			    || NM_STRCHAR_ANY (s, ch, NM_IN_SET (ch, ' ', '\t', '\n'))) {
+				/* there should be no such characters in the search entry. Also,
+				 * because glibc parser would treat them as line/word separator.
+				 *
+				 * Skip the value silently. */
+				continue;
 			}
 
+			if (search_base_idx > 0) {
+				if (str->len - search_base_idx + 1 + l > 254) {
+					/* this entry crosses the 256 character boundery. Older glibc versions
+					 * would truncate the entry at this point.
+					 *
+					 * Fill the line with spaces to cross the 256 char boundary and continue
+					 * afterwards. This way, the truncation happens between two search entries. */
+					while (str->len - search_base_idx < 257)
+						g_string_append_c (str, ' ');
+					search_base_idx = 0;
+				}
+			}
+
+			g_string_append_c (str, ' ');
+			g_string_append_len (str, s, l);
+		}
+		g_string_append_c (str, '\n');
+	}
+
+	if (nameservers && nameservers[0]) {
+		for (i = 0; nameservers[i]; i++) {
+			if (i == 3) {
+				g_string_append (str, "# NOTE: the libc resolver may not support more than 3 nameservers.\n");
+				g_string_append (str, "# The nameservers listed below may not be recognized.\n");
+			}
 			g_string_append (str, "nameserver ");
 			g_string_append (str, nameservers[i]);
 			g_string_append_c (str, '\n');
 		}
-		nameservers_str = g_string_free (str, FALSE);
 	}
 
-	return g_strdup_printf ("# Generated by NetworkManager\n%s%s%s",
-	                        searches_str ?: "",
-	                        nameservers_str ?: "",
-	                        options_str ?: "");
+	if (options && options[0]) {
+		g_string_append (str, "options");
+		for (i = 0; options[i]; i++) {
+			g_string_append_c (str, ' ');
+			g_string_append (str, options[i]);
+		}
+		g_string_append_c (str, '\n');
+	}
+
+	return g_string_free (str, FALSE);
+}
+
+char *
+nmtst_dns_create_resolv_conf (const char *const*searches,
+                              const char *const*nameservers,
+                              const char *const*options)
+{
+	return create_resolv_conf (searches, nameservers, options);
 }
 
 static gboolean
@@ -654,9 +686,9 @@ write_resolv_conf_contents (FILE *f,
 
 static gboolean
 write_resolv_conf (FILE *f,
-                   char **searches,
-                   char **nameservers,
-                   char **options,
+                   const char *const*searches,
+                   const char *const*nameservers,
+                   const char *const*options,
                    GError **error)
 {
 	gs_free char *content = NULL;
@@ -718,7 +750,11 @@ dispatch_resolvconf (NMDnsManager *self,
 		return SR_ERROR;
 	}
 
-	success = write_resolv_conf (f, searches, nameservers, options, error);
+	success = write_resolv_conf (f,
+	                             NM_CAST_STRV_CC (searches),
+	                             NM_CAST_STRV_CC (nameservers),
+	                             NM_CAST_STRV_CC (options),
+	                             error);
 	err = pclose (f);
 	if (err < 0) {
 		errnosv = errno;
@@ -757,9 +793,9 @@ _read_link_cached (const char *path, gboolean *is_cached, char **cached)
 
 static SpawnResult
 update_resolv_conf (NMDnsManager *self,
-                    char **searches,
-                    char **nameservers,
-                    char **options,
+                    const char *const*searches,
+                    const char *const*nameservers,
+                    const char *const*options,
                     GError **error,
                     NMDnsManagerResolvConfManager rc_manager)
 {
@@ -958,12 +994,11 @@ update_resolv_conf (NMDnsManager *self,
 static void
 compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[HASH_LEN])
 {
-	GChecksum *sum;
-	gsize len = HASH_LEN;
+	nm_auto_free_checksum GChecksum *sum = NULL;
 	NMDnsIPConfigData *ip_data;
 
 	sum = g_checksum_new (G_CHECKSUM_SHA1);
-	nm_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1));
+	nm_assert (HASH_LEN == g_checksum_type_get_length (G_CHECKSUM_SHA1));
 
 	if (global)
 		nm_global_dns_config_update_checksum (global, sum);
@@ -977,8 +1012,7 @@ compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer
 			nm_ip_config_hash (ip_data->ip_config, sum, TRUE);
 	}
 
-	g_checksum_get_digest (sum, buffer, &len);
-	g_checksum_free (sum);
+	nm_utils_checksum_get_digest_len (sum, buffer, HASH_LEN);
 }
 
 static gboolean
@@ -1066,7 +1100,6 @@ _collect_resolv_conf_data (NMDnsManager *self,
                            const char **out_nis_domain)
 {
 	NMDnsManagerPrivate *priv;
-	guint i, num, len;
 	NMResolvConfData rc = {
 		.nameservers = g_ptr_array_new (),
 		.searches = g_ptr_array_new (),
@@ -1136,17 +1169,6 @@ _collect_resolv_conf_data (NMDnsManager *self,
 		}
 	}
 
-	/* Per 'man resolv.conf', the search list is limited to 6 domains
-	 * totalling 256 characters.
-	 */
-	num = MIN (rc.searches->len, 6u);
-	for (i = 0, len = 0; i < num; i++) {
-		len += strlen (rc.searches->pdata[i]) + 1; /* +1 for spaces */
-		if (len > 256)
-			break;
-	}
-	g_ptr_array_set_size (rc.searches, i);
-
 	*out_searches = _ptrarray_to_strv (rc.searches);
 	*out_options = _ptrarray_to_strv (rc.options);
 	*out_nameservers = _ptrarray_to_strv (rc.nameservers);
@@ -1449,7 +1471,12 @@ update_dns (NMDnsManager *self,
 		switch (priv->rc_manager) {
 		case NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK:
 		case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE:
-			result = update_resolv_conf (self, searches, nameservers, options, error, priv->rc_manager);
+			result = update_resolv_conf (self,
+			                             NM_CAST_STRV_CC (searches),
+			                             NM_CAST_STRV_CC (nameservers),
+			                             NM_CAST_STRV_CC (options),
+			                             error,
+			                             priv->rc_manager);
 			resolv_conf_updated = TRUE;
 			/* If we have ended with no nameservers avoid updating again resolv.conf
 			 * on stop, as some external changes may be applied to it in the meanwhile */
@@ -1474,15 +1501,26 @@ update_dns (NMDnsManager *self,
 		if (result == SR_NOTFOUND) {
 			_LOGD ("update-dns: program not available, writing to resolv.conf");
 			g_clear_error (error);
-			result = update_resolv_conf (self, searches, nameservers, options, error, NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK);
+			result = update_resolv_conf (self,
+			                             NM_CAST_STRV_CC (searches),
+			                             NM_CAST_STRV_CC (nameservers),
+			                             NM_CAST_STRV_CC (options),
+			                             error,
+			                             NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK);
 			resolv_conf_updated = TRUE;
 		}
 	}
 
 	/* Unless we've already done it, update private resolv.conf in NMRUNDIR
 	   ignoring any errors */
-	if (!resolv_conf_updated)
-		update_resolv_conf (self, searches, nameservers, options, NULL, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED);
+	if (!resolv_conf_updated) {
+		update_resolv_conf (self,
+		                    NM_CAST_STRV_CC (searches),
+		                    NM_CAST_STRV_CC (nameservers),
+		                    NM_CAST_STRV_CC (options),
+		                    NULL,
+		                    NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED);
+	}
 
 	/* signal that resolv.conf was changed */
 	if (update && result == SR_SUCCESS)
@@ -1542,6 +1580,7 @@ plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data)
 	} else {
 		priv->plugin_ratelimit.num_restarts++;
 		if (priv->plugin_ratelimit.num_restarts > PLUGIN_RATELIMIT_BURST) {
+			plugin_failed (plugin, self);
 			_LOGW ("plugin %s child respawning too fast, delaying update for %u seconds",
 			        nm_dns_plugin_get_name (plugin), PLUGIN_RATELIMIT_DELAY);
 			priv->plugin_ratelimit.timer = g_timeout_add_seconds (PLUGIN_RATELIMIT_DELAY,