about summary refs log tree commit diff
path: root/src/nm-policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-policy.c')
-rw-r--r--src/nm-policy.c110
1 files changed, 79 insertions, 31 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 752cf44e..38a03613 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2004 - 2012 Red Hat, Inc.
+ * Copyright (C) 2004 - 2013 Red Hat, Inc.
  * Copyright (C) 2007 - 2008 Novell, Inc.
  */
 
@@ -62,6 +62,10 @@ struct NMPolicy {
 	NMDevice *default_device6;
 
 	HostnameThread *lookup;
+	guint32 lookup_ipv4_addr;          /* IPv4 for reverse lookup */
+	struct in6_addr *lookup_ipv6_addr; /* IPv6 for reverse lookup */
+	NMDnsManager *dns_manager;
+	gulong config_changed_id;
 
 	gint reset_retries_id;  /* idle handler for resetting the retries count */
 
@@ -229,14 +233,21 @@ _set_hostname (NMPolicy *policy,
                const char *new_hostname,
                const char *msg)
 {
-	NMDnsManager *dns_mgr;
-
 	/* The incoming hostname *can* be NULL, which will get translated to
 	 * 'localhost.localdomain' or such in the hostname policy code, but we
 	 * keep cur_hostname = NULL in the case because we need to know that
 	 * there was no valid hostname to start with.
 	 */
 
+	/* Clear lookup adresses if we have a hostname, so that we didn't
+	 * restart reverse lookup thread later.
+	 */
+	if (new_hostname) {
+		policy->lookup_ipv4_addr = 0;
+		g_free (policy->lookup_ipv6_addr);
+		policy->lookup_ipv6_addr = NULL;
+	}
+
 	/* Don't change the hostname or update DNS this is the first time we're
 	 * trying to change the hostname, and it's not actually changing.
 	 */
@@ -255,9 +266,7 @@ _set_hostname (NMPolicy *policy,
 	policy->cur_hostname = g_strdup (new_hostname);
 	policy->hostname_changed = TRUE;
 
-	dns_mgr = nm_dns_manager_get (NULL);
-	nm_dns_manager_set_hostname (dns_mgr, policy->cur_hostname);
-	g_object_unref (dns_mgr);
+	nm_dns_manager_set_hostname (policy->dns_manager, policy->cur_hostname);
 
 	if (nm_policy_set_system_hostname (policy->cur_hostname, msg))
 		nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL);
@@ -398,7 +407,8 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 		g_assert (addr4); /* checked for > 1 address above */
 
 		/* Start the hostname lookup thread */
-		policy->lookup = hostname4_thread_new (nm_ip4_address_get_address (addr4), lookup_callback, policy);
+		policy->lookup_ipv4_addr = nm_ip4_address_get_address (addr4);
+		policy->lookup = hostname4_thread_new (policy->lookup_ipv4_addr, lookup_callback, policy);
 	} else if (best6) {
 		NMIP6Config *ip6_config;
 		NMIP6Address *addr6;
@@ -416,7 +426,9 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
 		g_assert (addr6); /* checked for > 1 address above */
 
 		/* Start the hostname lookup thread */
-		policy->lookup = hostname6_thread_new (nm_ip6_address_get_address (addr6), lookup_callback, policy);
+		policy->lookup_ipv6_addr = g_malloc0 (sizeof (struct in6_addr));
+		memcpy (policy->lookup_ipv6_addr, nm_ip6_address_get_address (addr6), sizeof (struct in6_addr));
+		policy->lookup = hostname6_thread_new (policy->lookup_ipv6_addr, lookup_callback, policy);
 	}
 
 	if (!policy->lookup) {
@@ -1264,7 +1276,6 @@ device_state_changed (NMDevice *device,
 	NMIP4Config *ip4_config;
 	NMIP6Config *ip6_config;
 	NMSettingConnection *s_con;
-	NMDnsManager *dns_mgr;
 
 	if (connection)
 		g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (0));
@@ -1322,20 +1333,18 @@ device_state_changed (NMDevice *device,
 
 		/* Add device's new IPv4 and IPv6 configs to DNS */
 
-		dns_mgr = nm_dns_manager_get (NULL);
-		nm_dns_manager_begin_updates (dns_mgr, __func__);
+		nm_dns_manager_begin_updates (policy->dns_manager, __func__);
 
 		ip4_config = nm_device_get_ip4_config (device);
 		if (ip4_config)
-			nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+			nm_dns_manager_add_ip4_config (policy->dns_manager, ip_iface, ip4_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 		ip6_config = nm_device_get_ip6_config (device);
 		if (ip6_config)
-			nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+			nm_dns_manager_add_ip6_config (policy->dns_manager, ip_iface, ip6_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
 
 		update_routing_and_dns (policy, FALSE);
 
-		nm_dns_manager_end_updates (dns_mgr, __func__);
-		g_object_unref (dns_mgr);
+		nm_dns_manager_end_updates (policy->dns_manager, __func__);
 		break;
 	case NM_DEVICE_STATE_UNMANAGED:
 	case NM_DEVICE_STATE_UNAVAILABLE:
@@ -1387,16 +1396,14 @@ device_ip4_config_changed (NMDevice *device,
                            gpointer user_data)
 {
 	NMPolicy *policy = user_data;
-	NMDnsManager *dns_mgr;
 	const char *ip_iface = nm_device_get_ip_iface (device);
 	NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL;
 
-	dns_mgr = nm_dns_manager_get (NULL);
-	nm_dns_manager_begin_updates (dns_mgr, __func__);
+	nm_dns_manager_begin_updates (policy->dns_manager, __func__);
 
 	/* Old configs get removed immediately */
 	if (old_config)
-		nm_dns_manager_remove_ip4_config (dns_mgr, old_config);
+		nm_dns_manager_remove_ip4_config (policy->dns_manager, old_config);
 
 	/* Ignore IP config changes while the device is activating, because we'll
 	 * catch all the changes when the device moves to ACTIVATED state.
@@ -1404,8 +1411,8 @@ device_ip4_config_changed (NMDevice *device,
 	 */
 	if (!nm_device_is_activating (device)) {
 		if (new_config)
-			nm_dns_manager_add_ip4_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
-		update_ip4_dns (policy, dns_mgr);
+			nm_dns_manager_add_ip4_config (policy->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+		update_ip4_dns (policy, policy->dns_manager);
 
 		/* Only change routing if something actually changed */
 		diff = nm_ip4_config_diff (new_config, old_config);
@@ -1413,8 +1420,7 @@ device_ip4_config_changed (NMDevice *device,
 			update_ip4_routing (policy, TRUE);
 	}
 
-	nm_dns_manager_end_updates (dns_mgr, __func__);
-	g_object_unref (dns_mgr);
+	nm_dns_manager_end_updates (policy->dns_manager, __func__);
 }
 
 static void
@@ -1424,16 +1430,14 @@ device_ip6_config_changed (NMDevice *device,
                            gpointer user_data)
 {
 	NMPolicy *policy = user_data;
-	NMDnsManager *dns_mgr;
 	const char *ip_iface = nm_device_get_ip_iface (device);
 	NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL;
 
-	dns_mgr = nm_dns_manager_get (NULL);
-	nm_dns_manager_begin_updates (dns_mgr, __func__);
+	nm_dns_manager_begin_updates (policy->dns_manager, __func__);
 
 	/* Old configs get removed immediately */
 	if (old_config)
-		nm_dns_manager_remove_ip6_config (dns_mgr, old_config);
+		nm_dns_manager_remove_ip6_config (policy->dns_manager, old_config);
 
 	/* Ignore IP config changes while the device is activating, because we'll
 	 * catch all the changes when the device moves to ACTIVATED state.
@@ -1441,8 +1445,8 @@ device_ip6_config_changed (NMDevice *device,
 	 */
 	if (!nm_device_is_activating (device)) {
 		if (new_config)
-			nm_dns_manager_add_ip6_config (dns_mgr, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
-		update_ip6_dns (policy, dns_mgr);
+			nm_dns_manager_add_ip6_config (policy->dns_manager, ip_iface, new_config, NM_DNS_IP_CONFIG_TYPE_DEFAULT);
+		update_ip6_dns (policy, policy->dns_manager);
 
 		/* Only change routing if something actually changed */
 		diff = nm_ip6_config_diff (new_config, old_config);
@@ -1450,8 +1454,7 @@ device_ip6_config_changed (NMDevice *device,
 			update_ip6_routing (policy, TRUE);
 	}
 
-	nm_dns_manager_end_updates (dns_mgr, __func__);
-	g_object_unref (dns_mgr);
+	nm_dns_manager_end_updates (policy->dns_manager, __func__);
 }
 
 static void
@@ -1792,6 +1795,43 @@ firewall_started (NMFirewallManager *manager,
 }
 
 static void
+dns_config_changed (NMDnsManager *dns_manager, gpointer user_data)
+{
+	NMPolicy *policy = (NMPolicy *) user_data;
+
+	/* Restart a thread for reverse-DNS lookup after we are signalled that
+	 * DNS changed. Because the result from a previous run may not be right
+	 * (race in updating DNS and doing the reverse lookup).
+	 */
+
+	/* Stop a lookup thread if any. */
+	if (policy->lookup) {
+		hostname_thread_kill (policy->lookup);
+		policy->lookup = NULL;
+	}
+
+	/* Re-start the hostname lookup thread if we don't have hostname yet. */
+	if (policy->lookup_ipv4_addr) {
+		char buf[INET_ADDRSTRLEN];
+		struct in_addr addr = { .s_addr = policy->lookup_ipv4_addr };
+		
+		if (!inet_ntop (AF_INET, &addr, buf, sizeof (buf)))
+			strcpy (buf, "(unknown)");
+		nm_log_dbg (LOGD_DNS, "restarting IPv4 reverse-lookup thread for address %s'", buf);
+
+		policy->lookup = hostname4_thread_new (policy->lookup_ipv4_addr, lookup_callback, policy);
+	} else if (policy->lookup_ipv6_addr) {
+		char buf[INET6_ADDRSTRLEN];
+
+		if (!inet_ntop (AF_INET6, policy->lookup_ipv6_addr, buf, sizeof (buf)))
+			strcpy (buf, "(unknown)");
+		nm_log_dbg (LOGD_DNS, "restarting IPv6 reverse-lookup thread for address %s'", buf);
+
+		policy->lookup = hostname6_thread_new (policy->lookup_ipv6_addr, lookup_callback, policy);
+	}
+}
+
+static void
 connection_updated (NMSettings *settings,
                     NMConnection *connection,
                     gpointer user_data)
@@ -1917,6 +1957,10 @@ nm_policy_new (NMManager *manager, NMSettings *settings)
 	                       G_CALLBACK (firewall_started), policy);
 	policy->fw_started_id = id;
 
+	policy->dns_manager = nm_dns_manager_get (NULL);
+	policy->config_changed_id = g_signal_connect (policy->dns_manager, "config-changed",
+	                                              G_CALLBACK (dns_config_changed), policy);
+
 	_connect_manager_signal (policy, "state-changed", global_state_changed);
 	_connect_manager_signal (policy, "notify::" NM_MANAGER_HOSTNAME, hostname_changed);
 	_connect_manager_signal (policy, "notify::" NM_MANAGER_SLEEPING, sleeping_changed);
@@ -1955,6 +1999,7 @@ nm_policy_destroy (NMPolicy *policy)
 		hostname_thread_kill (policy->lookup);
 		policy->lookup = NULL;
 	}
+	g_free (policy->lookup_ipv6_addr);
 
 	g_slist_foreach (policy->pending_activation_checks, (GFunc) activate_data_free, NULL);
 	g_slist_free (policy->pending_activation_checks);
@@ -1965,6 +2010,9 @@ nm_policy_destroy (NMPolicy *policy)
 	g_signal_handler_disconnect (policy->fw_manager, policy->fw_started_id);
 	g_object_unref (policy->fw_manager);
 
+	g_signal_handler_disconnect (policy->dns_manager, policy->config_changed_id);
+	g_object_unref (policy->dns_manager);
+
 	for (iter = policy->manager_ids; iter; iter = g_slist_next (iter))
 		g_signal_handler_disconnect (policy->manager, GPOINTER_TO_UINT (iter->data));
 	g_slist_free (policy->manager_ids);