| /* 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; |
| } |