From 20e994b39261ec34df18ab78ddc2585e82f9b2d2 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Mar 2021 13:25:04 +0100 Subject: resolvectl: reword note about "raw record types" As noted in https://github.com/systemd/systemd/pull/17535#discussion_r534129256, "raw" is misleading in this context. Let's use a more descriptive term. --- src/resolve/resolvectl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 2bd18d2c6d..0ccd16892f 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -456,14 +456,14 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname); if (dns_name_is_single_label(name)) - log_notice("(Note that search domains are not appended when resolving raw record types. " - "Please specify fully qualified domain names when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.)"); + log_notice("(Note that search domains are not appended when --type= is specified. " + "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)"); r = idna_candidate(name, &idnafied); if (r < 0) return r; if (r > 0) - log_notice("(Note that IDNA translation is not applied when resolving raw record types. " + log_notice("(Note that IDNA translation is not applied when --type= is specified. " "Please specify translated domain names — i.e. '%s' — when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.", idnafied); -- cgit v1.2.3 From 75c9d6b5cf0b8f177867eef56edd01398e0b3e87 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Mar 2021 14:08:03 +0100 Subject: resolved: split out function to determine the local llmnr hostname --- src/resolve/meson.build | 2 + src/resolve/resolved-manager.c | 73 +++++------------------------------- src/resolve/resolved-util.c | 84 ++++++++++++++++++++++++++++++++++++++++++ src/resolve/resolved-util.h | 4 ++ 4 files changed, 99 insertions(+), 64 deletions(-) create mode 100644 src/resolve/resolved-util.c create mode 100644 src/resolve/resolved-util.h diff --git a/src/resolve/meson.build b/src/resolve/meson.build index e0568d71ac..b1d97736a3 100644 --- a/src/resolve/meson.build +++ b/src/resolve/meson.build @@ -13,6 +13,8 @@ basic_dns_sources = files(''' resolved-dns-answer.h resolved-dns-question.c resolved-dns-question.h + resolved-util.c + resolved-util.h dns-type.c dns-type.h '''.split()) diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index e815dacd7f..21154a7f85 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -33,6 +33,7 @@ #include "resolved-manager.h" #include "resolved-mdns.h" #include "resolved-resolv-conf.h" +#include "resolved-util.h" #include "resolved-varlink.h" #include "socket-util.h" #include "string-table.h" @@ -362,75 +363,17 @@ static int manager_clock_change_listen(Manager *m) { return 0; } -static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) { +static int determine_hostnames(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, *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". */ - - 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, 0); - if (r < 0) - return log_error_errno(r, "Failed to unescape hostname: %m"); - if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Couldn't find a single label in hostname."); - -#if HAVE_LIBIDN || HAVE_LIBIDN2 - r = dlopen_idn(); - if (r < 0) { - log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m"); - decoded = label; /* no decoding */ - } else -#endif - { -#if HAVE_LIBIDN2 - r = sym_idn2_to_unicode_8z8z(label, &utf8, 0); - if (r != IDN2_OK) - return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), - "Failed to undo IDNA: %s", sym_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) - r = k; - - if (!utf8_is_valid(label)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "System hostname is not UTF-8 clean."); - decoded = label; -#else - decoded = label; /* no decoding */ -#endif - } - - r = dns_label_escape_new(decoded, r, &n); + r = resolve_system_hostname(&h, &n); if (r < 0) - return log_error_errno(r, "Failed to escape hostname: %m"); - - if (is_localhost(n)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "System hostname is 'localhost', ignoring."); + return r; r = dns_name_concat(n, "local", 0, mdns_hostname); if (r < 0) @@ -501,9 +444,11 @@ static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, voi assert(m); - r = determine_hostname(&full_hostname, &llmnr_hostname, &mdns_hostname); - if (r < 0) + r = determine_hostnames(&full_hostname, &llmnr_hostname, &mdns_hostname); + if (r < 0) { + log_warning_errno(r, "Failed to determine the local hostname and LLMNR/mDNS names, ignoring: %m"); return 0; /* ignore invalid hostnames */ + } llmnr_hostname_changed = !streq(llmnr_hostname, m->llmnr_hostname); if (streq(full_hostname, m->full_hostname) && @@ -546,7 +491,7 @@ static int manager_watch_hostname(Manager *m) { (void) sd_event_source_set_description(m->hostname_event_source, "hostname"); - r = determine_hostname(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); + r = determine_hostnames(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); if (r < 0) { _cleanup_free_ char *d = NULL; diff --git a/src/resolve/resolved-util.c b/src/resolve/resolved-util.c new file mode 100644 index 0000000000..00abada426 --- /dev/null +++ b/src/resolve/resolved-util.c @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "dns-def.h" +#include "dns-domain.h" +#include "hostname-util.h" +#include "idn-util.h" +#include "resolved-util.h" +#include "utf8.h" + +int resolve_system_hostname(char **full_hostname, char **first_label) { + _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, *decoded; + int r; + + /* Return the full hostname in *full_hostname, if nonnull. + * + * Extract and normalize the first label of the locally configured hostname, check it's not + * "localhost", and return it in *first_label, if nonnull. */ + + 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, 0); + if (r < 0) + return log_debug_errno(r, "Failed to unescape hostname: %m"); + if (r == 0) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Couldn't find a single label in hostname."); + +#if HAVE_LIBIDN || HAVE_LIBIDN2 + r = dlopen_idn(); + if (r < 0) { + log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m"); + decoded = label; /* no decoding */ + } else +#endif + { +#if HAVE_LIBIDN2 + r = sym_idn2_to_unicode_8z8z(label, &utf8, 0); + if (r != IDN2_OK) + return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), + "Failed to undo IDNA: %s", sym_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_debug_errno(k, "Failed to undo IDNA: %m"); + if (k > 0) + r = k; + + if (!utf8_is_valid(label)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "System hostname is not UTF-8 clean."); + decoded = label; +#else + decoded = label; /* no decoding */ +#endif + } + + r = dns_label_escape_new(decoded, r, &n); + if (r < 0) + return log_debug_errno(r, "Failed to escape hostname: %m"); + + if (is_localhost(n)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "System hostname is 'localhost', ignoring."); + + if (full_hostname) + *full_hostname = TAKE_PTR(h); + if (first_label) + *first_label = TAKE_PTR(n); + return 0; +} diff --git a/src/resolve/resolved-util.h b/src/resolve/resolved-util.h new file mode 100644 index 0000000000..446b7c9f1b --- /dev/null +++ b/src/resolve/resolved-util.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +int resolve_system_hostname(char **full_hostname, char **first_label); -- cgit v1.2.3 From 058946d1f91ea3ab4d236959ac1671bbd16a1461 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Mar 2021 14:09:28 +0100 Subject: resolvectl: do not warn about single hostnames for names we synthesize https://github.com/systemd/systemd/pull/17535#discussion_r534005801 --- src/resolve/resolvectl.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 0ccd16892f..269151b9b1 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -19,6 +19,7 @@ #include "format-table.h" #include "format-util.h" #include "gcrypt-util.h" +#include "hostname-util.h" #include "main-func.h" #include "missing_network.h" #include "netlink-util.h" @@ -31,6 +32,7 @@ #include "resolvectl.h" #include "resolved-def.h" #include "resolved-dns-packet.h" +#include "resolved-util.h" #include "socket-netlink.h" #include "sort-util.h" #include "stdio-util.h" @@ -441,6 +443,25 @@ static int idna_candidate(const char *name, char **ret) { return false; } +static bool single_label_nonsynthetic(const char *name) { + _cleanup_free_ char *first_label = NULL; + int r; + + if (!dns_name_is_single_label(name)) + return false; + + if (is_localhost(name) || is_gateway_hostname(name)) + return false; + + r = resolve_system_hostname(NULL, &first_label); + if (r < 0) { + log_warning_errno(r, "Failed to determine the hostname: %m"); + return false; + } + + return !streq(name, first_label); +} + static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -455,7 +476,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname); - if (dns_name_is_single_label(name)) + if (single_label_nonsynthetic(name)) log_notice("(Note that search domains are not appended when --type= is specified. " "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)"); -- cgit v1.2.3 From 200b4f3d800afcb7c2fcba9fd6d1a35ffbee51c6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Mar 2021 14:14:38 +0100 Subject: resolvectl: suppress warning about --type for names with a dot People don't generally type the trailing dot by mistake, so let's treat this as indication that they want to resolve this particular hostname. --- src/resolve/resolvectl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index 269151b9b1..52bbae3293 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -476,7 +476,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname); - if (single_label_nonsynthetic(name)) + if (dns_name_dot_suffixed(name) == 0 && single_label_nonsynthetic(name)) log_notice("(Note that search domains are not appended when --type= is specified. " "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)"); -- cgit v1.2.3