1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "dns-def.h"
4 #include "dns-domain.h"
5 #include "hostname-util.h"
6 #include "idn-util.h"
7 #include "resolved-util.h"
8 #include "utf8.h"
9 
resolve_system_hostname(char ** full_hostname,char ** first_label)10 int resolve_system_hostname(char **full_hostname, char **first_label) {
11         _cleanup_free_ char *h = NULL, *n = NULL;
12 #if HAVE_LIBIDN2
13         _cleanup_free_ char *utf8 = NULL;
14 #elif HAVE_LIBIDN
15         int k;
16 #endif
17         char label[DNS_LABEL_MAX];
18         const char *p, *decoded;
19         int r;
20 
21         /* Return the full hostname in *full_hostname, if nonnull.
22          *
23          * Extract and normalize the first label of the locally configured hostname, check it's not
24          * "localhost", and return it in *first_label, if nonnull. */
25 
26         r = gethostname_strict(&h);
27         if (r < 0)
28                 return log_debug_errno(r, "Can't determine system hostname: %m");
29 
30         p = h;
31         r = dns_label_unescape(&p, label, sizeof label, 0);
32         if (r < 0)
33                 return log_debug_errno(r, "Failed to unescape hostname: %m");
34         if (r == 0)
35                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
36                                        "Couldn't find a single label in hostname.");
37 
38 #if HAVE_LIBIDN || HAVE_LIBIDN2
39         r = dlopen_idn();
40         if (r < 0) {
41                 log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m");
42                 decoded = label; /* no decoding */
43         } else
44 #endif
45         {
46 #if HAVE_LIBIDN2
47                 r = sym_idn2_to_unicode_8z8z(label, &utf8, 0);
48                 if (r != IDN2_OK)
49                         return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
50                                                "Failed to undo IDNA: %s", sym_idn2_strerror(r));
51                 assert(utf8_is_valid(utf8));
52 
53                 r = strlen(utf8);
54                 decoded = utf8;
55 #elif HAVE_LIBIDN
56                 k = dns_label_undo_idna(label, r, label, sizeof label);
57                 if (k < 0)
58                         return log_debug_errno(k, "Failed to undo IDNA: %m");
59                 if (k > 0)
60                         r = k;
61 
62                 if (!utf8_is_valid(label))
63                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
64                                                "System hostname is not UTF-8 clean.");
65                 decoded = label;
66 #else
67                 decoded = label; /* no decoding */
68 #endif
69         }
70 
71         r = dns_label_escape_new(decoded, r, &n);
72         if (r < 0)
73                 return log_debug_errno(r, "Failed to escape hostname: %m");
74 
75         if (is_localhost(n))
76                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
77                                        "System hostname is 'localhost', ignoring.");
78 
79         if (full_hostname)
80                 *full_hostname = TAKE_PTR(h);
81         if (first_label)
82                 *first_label = TAKE_PTR(n);
83         return 0;
84 }
85