#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)
if (r < 0)
return r;
}
+ /* do not warn about state here, since probably systemd already did */
return 0;
}
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;
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;
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;
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;
while (m->dns_queries)
dns_query_free(m->dns_queries);
- hashmap_free(m->dns_query_transactions);
+ hashmap_free(m->dns_transactions);
while ((l = hashmap_first(m->links)))
link_free(l);
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;
static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- DnsQueryTransaction *t = NULL;
+ DnsTransaction *t = NULL;
Manager *m = userdata;
int r;
return r;
if (dns_packet_validate_reply(p) > 0) {
- t = hashmap_get(m->dns_query_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
+ t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
if (!t)
return 0;
- dns_query_transaction_process_reply(t, p);
+ dns_transaction_process_reply(t, p);
} else
log_debug("Invalid DNS packet.");
static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- DnsQueryTransaction *t = NULL;
+ DnsTransaction *t = NULL;
Manager *m = userdata;
int r;
if (dns_packet_validate_reply(p) > 0) {
log_debug("Got reply packet for id %u", DNS_PACKET_ID(p));
- t = hashmap_get(m->dns_query_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
+ t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
if (!t)
return 0;
- dns_query_transaction_process_reply(t, p);
+ dns_transaction_process_reply(t, p);
} else if (dns_packet_validate_query(p) > 0) {
Link *l;
}
int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) {
- Link *l;
+ LinkAddress *a;
+
+ assert(m);
+
+ a = manager_find_address(m, family, in_addr);
+ if (a)
+ return a->link->ifindex;
+
+ return 0;
+}
+
+void manager_refresh_rrs(Manager *m) {
Iterator i;
+ Link *l;
assert(m);
- HASHMAP_FOREACH(l, m->links, i)
- if (link_find_address(l, family, in_addr))
- return l->ifindex;
+ 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;
+ uint64_t u;
+ char *h;
+
+ assert(m);
+
+ p = strchr(m->hostname, 0);
+ assert(p);
+
+ while (p > m->hostname) {
+ if (!strchr("0123456789", p[-1]))
+ break;
+
+ p--;
+ }
+
+ if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
+ u = 1;
+
+ u++;
+
+ if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->hostname), m->hostname, u) < 0)
+ return -ENOMEM;
+
+ log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->hostname, h);
+
+ free(m->hostname);
+ m->hostname = h;
+
+ manager_refresh_rrs(m);
return 0;
}
+
+LinkAddress* manager_find_address(Manager *m, int family, const union in_addr_union *in_addr) {
+ Iterator i;
+ Link *l;
+
+ assert(m);
+
+ HASHMAP_FOREACH(l, m->links, i) {
+ LinkAddress *a;
+
+ a = link_find_address(l, family, in_addr);
+ if (a)
+ return a;
+ }
+
+ return NULL;
+}
+
+int manager_our_packet(Manager *m, DnsPacket *p) {
+ assert(m);
+ assert(p);
+
+ return !!manager_find_address(m, p->family, &p->sender);
+}