]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/resolve/resolved-manager.c
Update mailmap and contributor list (#7006)
[thirdparty/systemd.git] / src / resolve / resolved-manager.c
index 92ade820ac6fdb1fa2d829c61549eac4ddfcf966..58fe572d3b9969c7bbfb2fa68c6d05a6498b69da 100644 (file)
 #include <poll.h>
 #include <sys/ioctl.h>
 
+#if HAVE_LIBIDN2
+#include <idn2.h>
+#endif
+
 #include "af-list.h"
 #include "alloc-util.h"
 #include "dirent-util.h"
@@ -322,32 +326,46 @@ static int manager_network_monitor_listen(Manager *m) {
         return 0;
 }
 
-static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
+static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
         _cleanup_free_ char *h = NULL, *n = NULL;
+#if HAVE_LIBIDN2
+        _cleanup_free_ char *utf8 = NULL;
+#elif HAVE_LIBIDN
+        int k;
+#endif
         char label[DNS_LABEL_MAX];
-        const char *p;
-        int r, k;
+        const char *p, *decoded;
+        int r;
 
+        assert(full_hostname);
         assert(llmnr_hostname);
         assert(mdns_hostname);
 
-        /* Extract and normalize the first label of the locally
-         * configured hostname, and check it's not "localhost". */
+        /* Extract and normalize the first label of the locally configured hostname, and check it's not "localhost". */
 
-        h = gethostname_malloc();
-        if (!h)
-                return log_oom();
+        r = gethostname_strict(&h);
+        if (r < 0)
+                return log_debug_errno(r, "Can't determine system hostname: %m");
 
         p = h;
-        r = dns_label_unescape(&p, label, sizeof(label));
+        r = dns_label_unescape(&p, label, sizeof label);
         if (r < 0)
                 return log_error_errno(r, "Failed to unescape host name: %m");
         if (r == 0) {
-                log_error("Couldn't find a single label in hosntame.");
+                log_error("Couldn't find a single label in hostname.");
                 return -EINVAL;
         }
 
-        k = dns_label_undo_idna(label, r, label, sizeof(label));
+#if HAVE_LIBIDN2
+        r = idn2_to_unicode_8z8z(label, &utf8, 0);
+        if (r != IDN2_OK)
+                return log_error("Failed to undo IDNA: %s", idn2_strerror(r));
+        assert(utf8_is_valid(utf8));
+
+        r = strlen(utf8);
+        decoded = utf8;
+#elif HAVE_LIBIDN
+        k = dns_label_undo_idna(label, r, label, sizeof label);
         if (k < 0)
                 return log_error_errno(k, "Failed to undo IDNA: %m");
         if (k > 0)
@@ -357,8 +375,12 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
                 log_error("System hostname is not UTF-8 clean.");
                 return -EINVAL;
         }
+        decoded = label;
+#else
+        decoded = label; /* no decoding */
+#endif
 
-        r = dns_label_escape_new(label, r, &n);
+        r = dns_label_escape_new(decoded, r, &n);
         if (r < 0)
                 return log_error_errno(r, "Failed to escape host name: %m");
 
@@ -374,32 +396,84 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
         *llmnr_hostname = n;
         n = NULL;
 
+        *full_hostname = h;
+        h = NULL;
+
+        return 0;
+}
+
+static const char *fallback_hostname(void) {
+
+        /* Determine the fall back hostname. For exposing this system to the outside world, we cannot have it to be
+         * "localhost" even if that's the compiled in hostname. In this case, let's revert to "linux" instead. */
+
+        if (is_localhost(FALLBACK_HOSTNAME))
+                return "linux";
+
+        return FALLBACK_HOSTNAME;
+}
+
+static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
+        _cleanup_free_ char *n = NULL, *m = NULL;
+        char label[DNS_LABEL_MAX], *h;
+        const char *p;
+        int r;
+
+        assert(full_hostname);
+        assert(llmnr_hostname);
+        assert(mdns_hostname);
+
+        p = fallback_hostname();
+        r = dns_label_unescape(&p, label, sizeof(label));
+        if (r < 0)
+                return log_error_errno(r, "Failed to unescape fallback host name: %m");
+
+        assert(r > 0); /* The fallback hostname must have at least one label */
+
+        r = dns_label_escape_new(label, r, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to escape fallback hostname: %m");
+
+        r = dns_name_concat(n, "local", &m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to concatenate mDNS hostname: %m");
+
+        h = strdup(fallback_hostname());
+        if (!h)
+                return log_oom();
+
+        *llmnr_hostname = n;
+        n = NULL;
+
+        *mdns_hostname = m;
+        m = NULL;
+
+        *full_hostname = h;
+
         return 0;
 }
 
 static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
-        _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL;
+        _cleanup_free_ char *full_hostname = NULL, *llmnr_hostname = NULL, *mdns_hostname = NULL;
         Manager *m = userdata;
         int r;
 
         assert(m);
 
-        r = determine_hostname(&llmnr_hostname, &mdns_hostname);
+        r = determine_hostname(&full_hostname, &llmnr_hostname, &mdns_hostname);
         if (r < 0)
                 return 0; /* ignore invalid hostnames */
 
-        if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname))
+        if (streq(full_hostname, m->full_hostname) &&
+            streq(llmnr_hostname, m->llmnr_hostname) &&
+            streq(mdns_hostname, m->mdns_hostname))
                 return 0;
 
-        log_info("System hostname changed to '%s'.", llmnr_hostname);
-
-        free(m->llmnr_hostname);
-        free(m->mdns_hostname);
-
-        m->llmnr_hostname = llmnr_hostname;
-        m->mdns_hostname = mdns_hostname;
+        log_info("System hostname changed to '%s'.", full_hostname);
 
-        llmnr_hostname = mdns_hostname = NULL;
+        free_and_replace(m->full_hostname, full_hostname);
+        free_and_replace(m->llmnr_hostname, llmnr_hostname);
+        free_and_replace(m->mdns_hostname, mdns_hostname);
 
         manager_refresh_rrs(m);
 
@@ -428,18 +502,15 @@ static int manager_watch_hostname(Manager *m) {
 
         (void) sd_event_source_set_description(m->hostname_event_source, "hostname");
 
-        r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname);
+        r = determine_hostname(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname);
         if (r < 0) {
-                log_info("Defaulting to hostname 'linux'.");
-                m->llmnr_hostname = strdup("linux");
-                if (!m->llmnr_hostname)
-                        return log_oom();
-
-                m->mdns_hostname = strdup("linux.local");
-                if (!m->mdns_hostname)
-                        return log_oom();
+                log_info("Defaulting to hostname '%s'.", fallback_hostname());
+
+                r = make_fallback_hostnames(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname);
+                if (r < 0)
+                        return r;
         } else
-                log_info("Using system hostname '%s'.", m->llmnr_hostname);
+                log_info("Using system hostname '%s'.", m->full_hostname);
 
         return 0;
 }
@@ -498,9 +569,10 @@ int manager_new(Manager **ret) {
         m->hostname_fd = -1;
 
         m->llmnr_support = RESOLVE_SUPPORT_YES;
-        m->mdns_support = RESOLVE_SUPPORT_NO;
+        m->mdns_support = RESOLVE_SUPPORT_YES;
         m->dnssec_mode = DEFAULT_DNSSEC_MODE;
         m->enable_cache = true;
+        m->dns_stub_listener_mode = DNS_STUB_LISTENER_UDP;
         m->read_resolv_conf = true;
         m->need_builtin_fallbacks = true;
         m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY;
@@ -511,7 +583,7 @@ int manager_new(Manager **ret) {
 
         r = manager_parse_config_file(m);
         if (r < 0)
-                return r;
+                log_warning_errno(r, "Failed to parse configuration file: %m");
 
         r = sd_event_default(&m->event);
         if (r < 0)
@@ -562,14 +634,6 @@ int manager_start(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = manager_llmnr_start(m);
-        if (r < 0)
-                return r;
-
-        r = manager_mdns_start(m);
-        if (r < 0)
-                return r;
-
         return 0;
 }
 
@@ -620,18 +684,20 @@ Manager *manager_free(Manager *m) {
 
         dns_resource_key_unref(m->llmnr_host_ipv4_key);
         dns_resource_key_unref(m->llmnr_host_ipv6_key);
+        dns_resource_key_unref(m->mdns_host_ipv4_key);
+        dns_resource_key_unref(m->mdns_host_ipv6_key);
 
         sd_event_source_unref(m->hostname_event_source);
         safe_close(m->hostname_fd);
+
+        free(m->full_hostname);
         free(m->llmnr_hostname);
         free(m->mdns_hostname);
 
         dns_trust_anchor_flush(&m->trust_anchor);
         manager_etc_hosts_flush(m);
 
-        free(m);
-
-        return NULL;
+        return mfree(m);
 }
 
 int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
@@ -657,7 +723,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         if (ms < 0)
                 return ms;
 
-        r = dns_packet_new(&p, protocol, ms);
+        r = dns_packet_new(&p, protocol, ms, DNS_PACKET_SIZE_MAX);
         if (r < 0)
                 return r;
 
@@ -675,7 +741,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         if (l == 0)
                 return 0;
         if (l < 0) {
-                if (errno == EAGAIN || errno == EINTR)
+                if (IN_SET(errno, EAGAIN, EINTR))
                         return 0;
 
                 return -errno;
@@ -1008,6 +1074,8 @@ void manager_refresh_rrs(Manager *m) {
 
         m->llmnr_host_ipv4_key = dns_resource_key_unref(m->llmnr_host_ipv4_key);
         m->llmnr_host_ipv6_key = dns_resource_key_unref(m->llmnr_host_ipv6_key);
+        m->mdns_host_ipv4_key = dns_resource_key_unref(m->mdns_host_ipv4_key);
+        m->mdns_host_ipv6_key = dns_resource_key_unref(m->mdns_host_ipv6_key);
 
         HASHMAP_FOREACH(l, m->links, i) {
                 link_add_rrs(l, true);
@@ -1147,8 +1215,14 @@ int manager_is_own_hostname(Manager *m, const char *name) {
                         return r;
         }
 
-        if (m->mdns_hostname)
-                return dns_name_equal(name, m->mdns_hostname);
+        if (m->mdns_hostname) {
+                r = dns_name_equal(name, m->mdns_hostname);
+                if (r != 0)
+                        return r;
+        }
+
+        if (m->full_hostname)
+                return dns_name_equal(name, m->full_hostname);
 
         return 0;
 }
@@ -1350,7 +1424,7 @@ void manager_cleanup_saved_user(Manager *m) {
                 if (!IN_SET(de->d_type, DT_UNKNOWN, DT_REG))
                         continue;
 
-                if (STR_IN_SET(de->d_name, ".", ".."))
+                if (dot_or_dot_dot(de->d_name))
                         continue;
 
                 r = parse_ifindex(de->d_name, &ifindex);