diff options
Diffstat (limited to 'src/systemd/src/shared/dns-domain.c')
-rw-r--r-- | src/systemd/src/shared/dns-domain.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c index 8b341461f0..fde2e4f29c 100644 --- a/src/systemd/src/shared/dns-domain.c +++ b/src/systemd/src/shared/dns-domain.c @@ -1283,18 +1283,44 @@ int dns_name_apply_idna(const char *name, char **ret) { #if defined(HAVE_LIBIDN2) int r; + _cleanup_free_ char *t = NULL; assert(name); assert(ret); - r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) ret, + r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); - if (r == IDN2_OK) + log_debug("idn2_lookup_u8: %s → %s", name, t); + if (r == IDN2_OK) { + if (!startswith(name, "xn--")) { + _cleanup_free_ char *s = NULL; + + r = idn2_to_unicode_8z8z(t, &s, 0); + if (r != IDN2_OK) { + log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s", + t, r, idn2_strerror(r)); + return 0; + } + + if (!streq_ptr(name, s)) { + log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.", + name, t, s); + return 0; + } + } + + *ret = t; + t = NULL; return 1; /* *ret has been written */ - else if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL)) + } + + log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r)); + if (r == IDN2_2HYPHEN) + /* The name has two hypens — forbidden by IDNA2008 in some cases */ + return 0; + if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL)) return -ENOSPC; - else - return -EINVAL; + return -EINVAL; #elif defined(HAVE_LIBIDN) _cleanup_free_ char *buf = NULL; size_t n = 0, allocated = 0; @@ -1331,7 +1357,7 @@ int dns_name_apply_idna(const char *name, char **ret) { else buf[n++] = '.'; - n +=r; + n += r; } if (n > DNS_HOSTNAME_MAX) @@ -1344,7 +1370,7 @@ int dns_name_apply_idna(const char *name, char **ret) { *ret = buf; buf = NULL; - return (int) n; + return 1; #else return 0; #endif |