diff options
author | Francesco Giudici <fgiudici@redhat.com> | 2017-02-17 16:22:30 +0100 |
---|---|---|
committer | Francesco Giudici <fgiudici@redhat.com> | 2017-03-24 15:18:08 +0100 |
commit | d34add6f0074f58ad0a232038c8ea26c74970d03 (patch) | |
tree | aa7b0b6d55f8482ae18ded8139339a2278e58731 /src | |
parent | b7557fa723991f6f49505794e39f9bddd22555a6 (diff) | |
download | NetworkManager-d34add6f0074f58ad0a232038c8ea26c74970d03.tar.gz |
policy: detect if the hostname was changed outside NetworkManager
When updating the hostname we can now detect if someone else changed
the hostname: if so, search for hostname candidates in the dhcp
configuration but avoid to fallback to the hostname saved when NM
started or querying dns for a reverse lookup of the current IP.
Diffstat (limited to 'src')
-rw-r--r-- | src/nm-policy.c | 89 |
1 files changed, 74 insertions, 15 deletions
diff --git a/src/nm-policy.c b/src/nm-policy.c index 5b04e7f231..1a489d4445 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -87,6 +87,8 @@ typedef struct { char *orig_hostname; /* hostname at NM start time */ char *cur_hostname; /* hostname we want to assign */ + char *last_hostname; /* last hostname NM set (to detect if someone else changed it in the meanwhile) */ + gboolean changing_hostname; /* hostname set operation still in progress */ GArray *ip6_prefix_delegations; /* pool of ip6 prefixes delegated to all devices */ } NMPolicyPrivate; @@ -412,6 +414,8 @@ settings_set_hostname_cb (const char *hostname, gboolean result, gpointer user_data) { + NMPolicy *self = NM_POLICY (user_data); + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); int ret = 0; if (!result) { @@ -426,8 +430,10 @@ settings_set_hostname_cb (const char *hostname, } } + priv->changing_hostname = FALSE; if (!ret) nm_dispatcher_call_hostname (NULL, NULL, NULL); + g_object_unref (self); } #define HOST_NAME_BUFSIZE (HOST_NAME_MAX + 2) @@ -440,6 +446,15 @@ _get_hostname (NMPolicy *self, char **hostname) g_assert (hostname && *hostname == NULL); + /* If there is an in-progress hostname change, return + * the last hostname set as would be set soon... + */ + if (priv->changing_hostname) { + _LOGT (LOGD_DNS, "gethostname: \"%s\" (last on set)", priv->last_hostname); + *hostname = g_strdup (priv->last_hostname); + return *hostname; + } + /* try to get the hostname via dbus... */ if (nm_settings_get_transient_hostname (priv->settings, hostname)) { _LOGT (LOGD_DNS, "gethostname: \"%s\" (from dbus)", *hostname); @@ -521,6 +536,11 @@ _set_hostname (NMPolicy *self, return; } + /* Keep track of the last set hostname */ + g_free (priv->last_hostname); + priv->last_hostname = g_strdup (name); + priv->changing_hostname = TRUE; + _LOGI (LOGD_DNS, "sethostname: '%s' (%s)", name, msg); /* Ask NMSettings to update the transient hostname using its @@ -528,7 +548,7 @@ _set_hostname (NMPolicy *self, nm_settings_set_transient_hostname (priv->settings, name, settings_set_hostname_cb, - NULL); + g_object_ref (self)); } static void @@ -563,19 +583,43 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); char *configured_hostname = NULL; + gs_free char *temp_hostname = NULL; const char *dhcp_hostname, *p; NMIP4Config *ip4_config; NMIP6Config *ip6_config; + gboolean external_hostname = FALSE; g_return_if_fail (self != NULL); nm_clear_g_cancellable (&priv->lookup_cancellable); + /* Check if the hostname was set externally to NM, so that in that case + * we can avoid to fallback to the one we got when we started. + * Consider "not specific" hostnames as equal. */ + if ( _get_hostname (self, &temp_hostname) + && !nm_streq0 (temp_hostname, priv->last_hostname) + && ( nm_utils_is_specific_hostname (temp_hostname) + || nm_utils_is_specific_hostname (priv->last_hostname))) { + external_hostname = TRUE; + _LOGI (LOGD_DNS, "current hostname was changed outside NetworkManager: '%s'", + temp_hostname); + + if (!nm_streq0 (temp_hostname, priv->orig_hostname)) { + /* Update original (fallback) hostname */ + g_free (priv->orig_hostname); + if (nm_utils_is_specific_hostname (temp_hostname)) { + priv->orig_hostname = temp_hostname; + temp_hostname = NULL; + } else + priv->orig_hostname = NULL; + } + } + /* Hostname precedence order: * * 1) a configured hostname (from settings) * 2) automatic hostname from the default device's config (DHCP, VPN, etc) - * 3) the original hostname when NM started + * 3) the last hostname set outside NM * 4) reverse-DNS of the best device's IPv4 address * */ @@ -595,14 +639,6 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) if (!best6) best6 = get_best_ip6_device (self, TRUE); - if (!best4 && !best6) { - /* No best device; fall back to original hostname or if there wasn't - * one, 'localhost.localdomain' - */ - _set_hostname (self, priv->orig_hostname, "no default device"); - return; - } - if (best4) { NMDhcp4Config *dhcp4_config; @@ -643,8 +679,20 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6) } } - /* If no automatically-configured hostname, try using the hostname from - * when NM started up. + /* If an hostname was set outside NetworkManager keep it */ + if (external_hostname) + return; + + if (!best4 && !best6) { + /* No best device; fall back to the last hostname set externally + * to NM or if there wasn't one, 'localhost.localdomain' + */ + _set_hostname (self, priv->orig_hostname, "no default device"); + return; + } + + /* If no automatically-configured hostname, try using the last hostname + * set externally to NM */ if (priv->orig_hostname) { _set_hostname (self, priv->orig_hostname, "from system startup"); @@ -2004,6 +2052,15 @@ dns_config_changed (NMDnsManager *dns_manager, gpointer user_data) /* Re-start the hostname lookup thread if we don't have hostname yet. */ if (priv->lookup_addr) { char *str = NULL; + gs_free char *hostname = NULL; + + /* Check if the hostname was externally set */ + if ( _get_hostname (self, &hostname) + && nm_utils_is_specific_hostname (hostname) + && !nm_streq0 (hostname, priv->last_hostname)) { + g_clear_object (&priv->lookup_addr); + return; + } _LOGD (LOGD_DNS, "restarting reverse-lookup thread for address %s", (str = g_inet_address_to_string (priv->lookup_addr))); @@ -2213,11 +2270,12 @@ constructed (GObject *object) /* Grab hostname on startup and use that if nothing provides one */ if (_get_hostname (self, &hostname)) { + /* init last_hostname */ + priv->last_hostname = hostname; + /* only cache it if it's a valid hostname */ if (nm_utils_is_specific_hostname (hostname)) - priv->orig_hostname = hostname; - else - g_free (hostname); + priv->orig_hostname = g_strdup (hostname); } priv->firewall_manager = g_object_ref (nm_firewall_manager_get ()); @@ -2310,6 +2368,7 @@ dispose (GObject *object) g_clear_pointer (&priv->orig_hostname, g_free); g_clear_pointer (&priv->cur_hostname, g_free); + g_clear_pointer (&priv->last_hostname, g_free); if (priv->settings) { g_signal_handlers_disconnect_by_data (priv->settings, priv); |