Commit 773c006a authored by Dan Williams's avatar Dan Williams

policy: support IPv6 address reverse-lookup for hostname too

parent 276fed03
......@@ -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 (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,56 @@ 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);
ht->lock = g_mutex_new ();
ht->callback = callback;
ht->user_data = user_data;
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);
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);
......@@ -114,14 +162,24 @@ 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->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);
ht = NULL;
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);
......
......@@ -34,9 +34,13 @@ typedef void (*HostnameThreadCallback) (HostnameThread *ht,
const char *hostname,
gpointer user_data);
HostnameThread * hostname_thread_new (guint32 ip4_addr,
HostnameThreadCallback callback,
gpointer user_data);
HostnameThread * hostname4_thread_new (guint32 ip4_addr,
HostnameThreadCallback callback,
gpointer user_data);
HostnameThread * hostname6_thread_new (const struct in6_addr *ip6_addr,
HostnameThreadCallback callback,
gpointer user_data);
void hostname_thread_free (HostnameThread *ht);
......
......@@ -255,13 +255,12 @@ lookup_callback (HostnameThread *thread,
}
static void
update_system_hostname (NMPolicy *policy, NMDevice *best)
update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
{
char *configured_hostname = NULL;
NMActRequest *best_req = NULL;
NMDHCP4Config *dhcp4_config;
NMIP4Config *ip4_config;
NMIP4Address *addr;
NMActRequest *best_req4 = NULL;
NMActRequest *best_req6 = NULL;
const char *dhcp_hostname, *p;
g_return_if_fail (policy != NULL);
......@@ -288,10 +287,12 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
}
/* Try automatically determined hostname from the best device's IP config */
if (!best)
best = get_best_ip4_device (policy->manager, &best_req);
if (!best4)
best4 = get_best_ip4_device (policy->manager, &best_req4);
if (!best6)
best6 = get_best_ip6_device (policy->manager, &best_req6);
if (!best) {
if (!best4 && !best6) {
/* No best device; fall back to original hostname or if there wasn't
* one, 'localhost.localdomain'
*/
......@@ -299,22 +300,43 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
return;
}
/* Grab a hostname out of the device's DHCP4 config */
dhcp4_config = nm_device_get_dhcp4_config (best);
if (dhcp4_config) {
const char *dhcp4_hostname, *p;
p = dhcp4_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name");
if (dhcp4_hostname && strlen (dhcp4_hostname)) {
/* Sanity check */
while (*p) {
if (!isblank (*p++)) {
_set_hostname (dhcp4_hostname, "from DHCP");
return;
if (best4) {
NMDHCP4Config *dhcp4_config;
/* Grab a hostname out of the device's DHCP4 config */
dhcp4_config = nm_device_get_dhcp4_config (best4);
if (dhcp4_config) {
p = dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name");
if (dhcp_hostname && strlen (dhcp_hostname)) {
/* Sanity check; strip leading spaces */
while (*p) {
if (!isblank (*p++)) {
_set_hostname (dhcp_hostname, "from DHCPv4");
return;
}
}
nm_log_warn (LOGD_DNS, "DHCPv4-provided hostname '%s' looks invalid; ignoring it",
dhcp_hostname);
}
}
} else if (best6) {
NMDHCP6Config *dhcp6_config;
/* Grab a hostname out of the device's DHCP4 config */
dhcp6_config = nm_device_get_dhcp6_config (best6);
if (dhcp6_config) {
p = dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "host_name");
if (dhcp_hostname && strlen (dhcp_hostname)) {
/* Sanity check; strip leading spaces */
while (*p) {
if (!isblank (*p++)) {
_set_hostname (dhcp_hostname, "from DHCPv6");
return;
}
}
nm_log_warn (LOGD_DNS, "DHCPv6-provided hostname '%s' looks invalid; ignoring it",
dhcp_hostname);
}
nm_log_warn (LOGD_DNS, "DHCP-provided hostname '%s' looks invalid; ignoring it",
dhcp4_hostname);
}
}
......@@ -326,23 +348,47 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
return;
}
/* No configured hostname, no automatically determined hostname, and
* no bootup hostname. Start reverse DNS of the current IP address.
/* No configured hostname, no automatically determined hostname, and no
* bootup hostname. Start reverse DNS of the current IPv4 or IPv6 address.
*/
ip4_config = nm_device_get_ip4_config (best);
if ( !ip4_config
|| (nm_ip4_config_get_num_nameservers (ip4_config) == 0)
|| (nm_ip4_config_get_num_addresses (ip4_config) == 0)) {
/* No valid IP4 config (!!); fall back to localhost.localdomain */
_set_hostname (NULL, "no IPv4 config");
return;
}
if (best4) {
NMIP4Config *ip4_config;
NMIP4Address *addr4;
ip4_config = nm_device_get_ip4_config (best4);
if ( !ip4_config
|| (nm_ip4_config_get_num_nameservers (ip4_config) == 0)
|| (nm_ip4_config_get_num_addresses (ip4_config) == 0)) {
/* No valid IP4 config (!!); fall back to localhost.localdomain */
_set_hostname (NULL, "no IPv4 config");
return;
}
addr4 = nm_ip4_config_get_address (ip4_config, 0);
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);
} else if (best6) {
NMIP6Config *ip6_config;
NMIP6Address *addr6;
ip6_config = nm_device_get_ip6_config (best6);
if ( !ip6_config
|| (nm_ip6_config_get_num_nameservers (ip6_config) == 0)
|| (nm_ip6_config_get_num_addresses (ip6_config) == 0)) {
/* No valid IP6 config (!!); fall back to localhost.localdomain */
_set_hostname (NULL, "no IPv6 config");
return;
}
addr = nm_ip4_config_get_address (ip4_config, 0);
g_assert (addr); /* checked for > 1 address above */
addr6 = nm_ip6_config_get_address (ip6_config, 0);
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);
}
/* Start the hostname lookup thread */
policy->lookup = hostname_thread_new (nm_ip4_address_get_address (addr), lookup_callback, policy);
if (!policy->lookup) {
/* Fall back to 'localhost.localdomain' */
_set_hostname (NULL, "error starting hostname thread");
......@@ -603,7 +649,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
update_ip6_routing_and_dns (policy, force_update);
/* Update the system hostname */
update_system_hostname (policy, policy->default_device4);
update_system_hostname (policy, policy->default_device4, policy->default_device6);
}
typedef struct {
......@@ -711,7 +757,7 @@ global_state_changed (NMManager *manager, NMState state, gpointer user_data)
static void
hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
{
update_system_hostname ((NMPolicy *) user_data, NULL);
update_system_hostname ((NMPolicy *) user_data, NULL, NULL);
}
static void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment