summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-07-31 19:54:43 +0200
committerLennart Poettering <lennart@poettering.net>2014-07-31 19:54:43 +0200
commiteb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92 (patch)
tree4f59339c855602cf6ffb1fb633bf09be0c670294
parent85818582574bcd1c3707c2a4609c9e283e47493f (diff)
hostnamed: watch system hostname changes and update LLMNR RRs accordingly
-rw-r--r--src/resolve/resolved-manager.c128
-rw-r--r--src/resolve/resolved.h5
2 files changed, 119 insertions, 14 deletions
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 72034c1f48..6987c29e07 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -34,6 +34,8 @@
#include "socket-util.h"
#include "af-list.h"
#include "resolved.h"
+#include "utf8.h"
+#include "resolved-dns-domain.h"
#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
@@ -384,6 +386,92 @@ int manager_parse_config_file(Manager *m) {
false, false, true, m);
}
+static int determine_hostname(char **ret) {
+ _cleanup_free_ char *h = NULL, *n = NULL;
+ int r;
+
+ assert(ret);
+
+ h = gethostname_malloc();
+ if (!h)
+ return log_oom();
+
+ if (!utf8_is_valid(h)) {
+ log_error("System hostname is not UTF-8 clean.");
+ return -EINVAL;
+ }
+
+ r = dns_name_normalize(h, &n);
+ if (r < 0) {
+ log_error("System hostname '%s' cannot be normalized.", h);
+ return r;
+ }
+
+ *ret = n;
+ n = NULL;
+
+ return 0;
+}
+
+static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
+ _cleanup_free_ char *h = NULL;
+ Manager *m = userdata;
+ int r;
+
+ assert(m);
+
+ r = determine_hostname(&h);
+ if (r < 0)
+ return 0; /* ignore invalid hostnames */
+
+ if (streq(h, m->hostname))
+ return 0;
+
+ log_info("System hostname changed to '%s'.", h);
+ free(m->hostname);
+ m->hostname = h;
+ h = NULL;
+
+ manager_refresh_rrs(m);
+
+ return 0;
+}
+
+static int manager_watch_hostname(Manager *m) {
+ _cleanup_free_ char *h = NULL;
+ int r;
+
+ assert(m);
+
+ m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
+ if (m->hostname_fd < 0) {
+ log_warning("Failed to watch hostname: %m");
+ return 0;
+ }
+
+ r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
+ if (r < 0) {
+ if (r == -EPERM)
+ /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
+ m->hostname_fd = safe_close(m->hostname_fd);
+ else {
+ log_error("Failed to add hostname event source: %s", strerror(-r));
+ return r;
+ }
+ }
+
+ r = determine_hostname(&m->hostname);
+ if (r < 0) {
+ log_info("Defaulting to hostname 'linux'.");
+ m->hostname = strdup("linux");
+ if (!m->hostname)
+ return log_oom();
+ } else
+ log_info("Using system hostname '%s'.", m->hostname);
+
+ return 0;
+}
+
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@@ -397,6 +485,7 @@ int manager_new(Manager **ret) {
m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
+ m->hostname_fd = -1;
m->use_llmnr = true;
@@ -404,10 +493,6 @@ int manager_new(Manager **ret) {
if (r < 0)
return r;
- m->hostname = gethostname_malloc();
- if (!m->hostname)
- return -ENOMEM;
-
r = sd_event_default(&m->event);
if (r < 0)
return r;
@@ -417,6 +502,10 @@ int manager_new(Manager **ret) {
sd_event_set_watchdog(m->event, true);
+ r = manager_watch_hostname(m);
+ if (r < 0)
+ return r;
+
r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
if (r < 0)
return r;
@@ -497,7 +586,11 @@ Manager *manager_free(Manager *m) {
dns_resource_key_unref(m->host_ipv4_key);
dns_resource_key_unref(m->host_ipv6_key);
+
+ safe_close(m->hostname_fd);
+ sd_event_source_unref(m->hostname_event_source);
free(m->hostname);
+
free(m);
return NULL;
@@ -1408,12 +1501,25 @@ int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_a
return 0;
}
+void manager_refresh_rrs(Manager *m) {
+ Iterator i;
+ Link *l;
+
+ assert(m);
+
+ m->host_ipv4_key = dns_resource_key_unref(m->host_ipv4_key);
+ m->host_ipv6_key = dns_resource_key_unref(m->host_ipv6_key);
+
+ HASHMAP_FOREACH(l, m->links, i) {
+ link_add_rrs(l, true);
+ link_add_rrs(l, false);
+ }
+}
+
int manager_next_hostname(Manager *m) {
const char *p;
- Iterator i;
uint64_t u;
char *h;
- Link *l;
assert(m);
@@ -1435,18 +1541,12 @@ int manager_next_hostname(Manager *m) {
if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->hostname), m->hostname, u) < 0)
return -ENOMEM;
- log_info("Hostname conflict, changing local hostname from '%s' to '%s'.", m->hostname, h);
+ log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->hostname, h);
free(m->hostname);
m->hostname = h;
- m->host_ipv4_key = dns_resource_key_unref(m->host_ipv4_key);
- m->host_ipv6_key = dns_resource_key_unref(m->host_ipv6_key);
-
- HASHMAP_FOREACH(l, m->links, i) {
- link_add_rrs(l, true);
- link_add_rrs(l, false);
- }
+ manager_refresh_rrs(m);
return 0;
}
diff --git a/src/resolve/resolved.h b/src/resolve/resolved.h
index 07560553b9..34eb7b5c5a 100644
--- a/src/resolve/resolved.h
+++ b/src/resolve/resolved.h
@@ -90,6 +90,10 @@ struct Manager {
char *hostname;
DnsResourceKey *host_ipv4_key;
DnsResourceKey *host_ipv6_key;
+
+ /* Watch the system hostname */
+ int hostname_fd;
+ sd_event_source *hostname_event_source;
};
/* Manager */
@@ -120,6 +124,7 @@ int manager_ifindex_is_loopback(Manager *m, int ifindex);
int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr);
LinkAddress* manager_find_address(Manager *m, int family, const union in_addr_union *in_addr);
+void manager_refresh_rrs(Manager *m);
int manager_next_hostname(Manager *m);
int manager_our_packet(Manager *m, DnsPacket *p);