about summary refs log tree commit diff
path: root/src/nm-policy-hostname.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-policy-hostname.c')
-rw-r--r--src/nm-policy-hostname.c116
1 files changed, 95 insertions, 21 deletions
diff --git a/src/nm-policy-hostname.c b/src/nm-policy-hostname.c
index a273a920..42a2e0f9 100644
--- a/src/nm-policy-hostname.c
+++ b/src/nm-policy-hostname.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <netdb.h>
 #include <ctype.h>
+#include <arpa/inet.h>
 
 #include <glib.h>
 
@@ -40,7 +41,10 @@ struct HostnameThread {
 	gboolean dead;
 	int ret;
 
-	guint32 ip4_addr;
+	struct sockaddr_in addr4;
+	struct sockaddr_in6 addr6;
+	struct sockaddr *addr;
+	size_t addr_size;
 	char hostname[NI_MAXHOST + 1];
 
 	HostnameThreadCallback callback;
@@ -53,9 +57,10 @@ hostname_thread_run_cb (gpointer user_data)
 	HostnameThread *ht = (HostnameThread *) user_data;
 	const char *hostname = NULL;
 
-	if (strlen (ht->hostname))
+	if (strlen (ht->hostname) && strcmp (ht->hostname, "."))
 		hostname = ht->hostname;
 
+	nm_log_dbg (LOGD_DNS, "(%p) calling address reverse-lookup result handler", ht);
 	(*ht->callback) (ht, ht->ret, hostname, ht->user_data);
 	return FALSE;
 }
@@ -64,9 +69,10 @@ static gpointer
 hostname_thread_worker (gpointer data)
 {
 	HostnameThread *ht = (HostnameThread *) data;
-	struct sockaddr_in addr;
 	int i;
 
+	nm_log_dbg (LOGD_DNS, "(%p) starting address reverse-lookup", ht);
+
 	g_mutex_lock (ht->lock);
 	if (ht->dead) {
 		g_mutex_unlock (ht->lock);
@@ -74,21 +80,22 @@ hostname_thread_worker (gpointer data)
 	}
 	g_mutex_unlock (ht->lock);
 
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = ht->ip4_addr;
-
-	ht->ret = getnameinfo ((struct sockaddr *) &addr, sizeof (struct sockaddr_in),
-	                       ht->hostname, NI_MAXHOST, NULL, 0,
-	                       NI_NAMEREQD);
+	ht->ret = getnameinfo (ht->addr, ht->addr_size, ht->hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
 	if (ht->ret == 0) {
+		nm_log_dbg (LOGD_DNS, "(%p) address reverse-lookup returned hostname '%s'",
+		            ht, ht->hostname);
 		for (i = 0; i < strlen (ht->hostname); i++)
 			ht->hostname[i] = tolower (ht->hostname[i]);
+	} else {
+		nm_log_dbg (LOGD_DNS, "(%p) address reverse-lookup failed: (%d) %s",
+		            ht, ht->ret, gai_strerror (ht->ret));
 	}
 
 	/* Don't track the idle handler ID because by the time the g_idle_add()
 	 * returns the ID, the handler may already have run and freed the
 	 * HostnameThread.
 	 */
+	nm_log_dbg (LOGD_DNS, "(%p) scheduling address reverse-lookup result handler", ht);
 	g_idle_add (hostname_thread_run_cb, ht);
 	return (gpointer) TRUE;
 }
@@ -98,15 +105,21 @@ hostname_thread_free (HostnameThread *ht)
 {
 	g_return_if_fail (ht != NULL);
 
+	nm_log_dbg (LOGD_DNS, "(%p) freeing reverse-lookup thread", ht);
+
 	g_mutex_free (ht->lock);
 	memset (ht, 0, sizeof (HostnameThread));
 	g_free (ht);
 }
 
 HostnameThread *
-hostname_thread_new (guint32 ip4_addr, HostnameThreadCallback callback, gpointer user_data)
+hostname4_thread_new (guint32 ip4_addr,
+                      HostnameThreadCallback callback,
+                      gpointer user_data)
 {
 	HostnameThread *ht;
+	struct sockaddr_in addr4;
+	char buf[INET_ADDRSTRLEN + 1];
 
 	ht = g_malloc0 (sizeof (HostnameThread));
 	g_assert (ht);
@@ -114,14 +127,59 @@ hostname_thread_new (guint32 ip4_addr, HostnameThreadCallback callback, gpointer
 	ht->lock = g_mutex_new ();
 	ht->callback = callback;
 	ht->user_data = user_data;
-	ht->ip4_addr = ip4_addr;
+
+	ht->addr4.sin_family = AF_INET;
+	ht->addr4.sin_addr.s_addr = ip4_addr;
+	ht->addr = (struct sockaddr *) &ht->addr4;
+	ht->addr_size = sizeof (ht->addr4);
 
 	ht->thread = g_thread_create (hostname_thread_worker, ht, FALSE, NULL);
 	if (!ht->thread) {
 		hostname_thread_free (ht);
-		ht = NULL;
+		return NULL;
 	}
 
+	if (!inet_ntop (AF_INET, &addr4.sin_addr, buf, sizeof (buf)))
+		strcpy (buf, "(unknown)");
+
+	nm_log_dbg (LOGD_DNS, "(%p) started IPv4 reverse-lookup thread for address '%s'",
+	            ht, buf);
+
+	return ht;
+}
+
+HostnameThread *
+hostname6_thread_new (const struct in6_addr *ip6_addr,
+                      HostnameThreadCallback callback,
+                      gpointer user_data)
+{
+	HostnameThread *ht;
+	char buf[INET6_ADDRSTRLEN + 1];
+
+	ht = g_malloc0 (sizeof (HostnameThread));
+	g_assert (ht);
+
+	ht->lock = g_mutex_new ();
+	ht->callback = callback;
+	ht->user_data = user_data;
+
+	ht->addr6.sin6_family = AF_INET6;
+	ht->addr6.sin6_addr = *ip6_addr;
+	ht->addr = (struct sockaddr *) &ht->addr6;
+	ht->addr_size = sizeof (ht->addr6);
+
+	ht->thread = g_thread_create (hostname_thread_worker, ht, FALSE, NULL);
+	if (!ht->thread) {
+		hostname_thread_free (ht);
+		return NULL;
+	}
+
+	if (!inet_ntop (AF_INET, ip6_addr, buf, sizeof (buf)))
+		strcpy (buf, "(unknown)");
+
+	nm_log_dbg (LOGD_DNS, "(%p) started IPv6 reverse-lookup thread for address '%s'",
+	            ht, buf);
+
 	return ht;
 }
 
@@ -130,6 +188,8 @@ hostname_thread_kill (HostnameThread *ht)
 {
 	g_return_if_fail (ht != NULL);
 
+	nm_log_dbg (LOGD_DNS, "(%p) stopping reverse-lookup thread", ht);
+
 	g_mutex_lock (ht->lock);
 	ht->dead = TRUE;
 	g_mutex_unlock (ht->lock);
@@ -145,20 +205,24 @@ hostname_thread_is_dead (HostnameThread *ht)
 
 /************************************************************************/
 
-#define FALLBACK_HOSTNAME "localhost.localdomain"
+#define FALLBACK_HOSTNAME4 "localhost.localdomain"
+#define FALLBACK_HOSTNAME6 "localhost6.localdomain6"
 
 gboolean
-nm_policy_set_system_hostname (const char *new_hostname, const char *msg)
+nm_policy_set_system_hostname (const char *new_hostname,
+                               const char *ip4_addr,
+                               const char *ip6_addr,
+                               const char *msg)
 {
 	char old_hostname[HOST_NAME_MAX + 1];
 	int ret = 0;
 	const char *name;
-	gboolean set_hostname = TRUE, changed = FALSE;
+	gboolean set_hostname = TRUE, changed = FALSE, old_valid = TRUE;
 
 	if (new_hostname)
 		g_warn_if_fail (strlen (new_hostname));
 
-	name = (new_hostname && strlen (new_hostname)) ? new_hostname : FALLBACK_HOSTNAME;
+	name = (new_hostname && strlen (new_hostname)) ? new_hostname : FALLBACK_HOSTNAME4;
 
 	old_hostname[HOST_NAME_MAX] = '\0';
 	errno = 0;
@@ -166,11 +230,15 @@ nm_policy_set_system_hostname (const char *new_hostname, const char *msg)
 	if (ret != 0) {
 		nm_log_warn (LOGD_DNS, "couldn't get the system hostname: (%d) %s",
 		             errno, strerror (errno));
+		old_valid = FALSE;
 	} else {
 		/* Don't set the hostname if it isn't actually changing */
 		if (   (new_hostname && !strcmp (old_hostname, new_hostname))
-		    || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME)))
+		    || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME4)))
 			set_hostname = FALSE;
+
+		if (old_hostname[0] == '\0')
+			old_valid = FALSE;
 	}
 
 	if (set_hostname) {
@@ -190,13 +258,19 @@ nm_policy_set_system_hostname (const char *new_hostname, const char *msg)
 	 * nm_policy_hosts_update_etc_hosts() will just return and won't touch
 	 * /etc/hosts at all.
 	 */
-	if (!nm_policy_hosts_update_etc_hosts (name, FALLBACK_HOSTNAME, &changed)) {
+	if (!nm_policy_hosts_update_etc_hosts (name,
+	                                       old_valid ? old_hostname : NULL,
+	                                       FALLBACK_HOSTNAME4,
+	                                       FALLBACK_HOSTNAME6,
+	                                       ip4_addr,
+	                                       ip6_addr,
+	                                       &changed)) {
 		/* error updating /etc/hosts; fallback to localhost.localdomain */
-		nm_log_info (LOGD_DNS, "Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)");
-		ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME));
+		nm_log_info (LOGD_DNS, "Setting system hostname to '" FALLBACK_HOSTNAME4 "' (error updating /etc/hosts)");
+		ret = sethostname (FALLBACK_HOSTNAME4, strlen (FALLBACK_HOSTNAME4));
 		if (ret != 0) {
 			nm_log_warn (LOGD_DNS, "couldn't set the fallback system hostname (%s): (%d) %s",
-			             FALLBACK_HOSTNAME, errno, strerror (errno));
+			             FALLBACK_HOSTNAME4, errno, strerror (errno));
 		}
 	}