resolved: allow resolution of names which libidn2 considers invalid (#6315)
https://tools.ietf.org/html/rfc5891#section-4.2.3.1 says that > The Unicode string MUST NOT contain "--" (two consecutive hyphens) in the third > and fourth character positions and MUST NOT start or end with a "-" (hyphen). This means that libidn2 refuses to encode such names. Let's just resolve them without trying to use IDN.
This commit is contained in:
parent
e3e42fc2b5
commit
ad1f3fe6a8
|
@ -345,10 +345,10 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
|
|||
return r;
|
||||
|
||||
r = dns_question_new_address(&question_idna, family, hostname, true);
|
||||
if (r < 0)
|
||||
if (r < 0 && r != -EALREADY)
|
||||
return r;
|
||||
|
||||
r = dns_query_new(m, &q, question_utf8, question_idna, ifindex, flags);
|
||||
r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, ifindex, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -309,8 +309,14 @@ int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bo
|
|||
r = dns_name_apply_idna(name, &buf);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
if (r > 0 && !streq(name, buf))
|
||||
name = buf;
|
||||
else
|
||||
/* We did not manage to create convert the idna name, or it's
|
||||
* the same as the original name. We assume the caller already
|
||||
* created an uncoverted question, so let's not repeat work
|
||||
* unnecessarily. */
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
q = dns_question_new(family == AF_UNSPEC ? 2 : 1);
|
||||
|
|
|
@ -1282,10 +1282,13 @@ int dns_name_apply_idna(const char *name, char **ret) {
|
|||
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
|
||||
if (r == IDN2_OK)
|
||||
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: %s", name, 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;
|
||||
|
@ -1322,7 +1325,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
|
|||
else
|
||||
buf[n++] = '.';
|
||||
|
||||
n +=r;
|
||||
n += r;
|
||||
}
|
||||
|
||||
if (n > DNS_HOSTNAME_MAX)
|
||||
|
@ -1335,7 +1338,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
|
|||
*ret = buf;
|
||||
buf = NULL;
|
||||
|
||||
return (int) n;
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
|
|
@ -607,24 +607,53 @@ static void test_dns_name_common_suffix(void) {
|
|||
test_dns_name_common_suffix_one("FOO.BAR", "tEST.bAR", "BAR");
|
||||
}
|
||||
|
||||
static void test_dns_name_apply_idna_one(const char *s, const char *result) {
|
||||
#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
|
||||
static void test_dns_name_apply_idna_one(const char *s, int expected, const char *result) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
assert_se(dns_name_apply_idna(s, &buf) >= 0);
|
||||
assert_se(dns_name_equal(buf, result) > 0);
|
||||
#endif
|
||||
int r;
|
||||
|
||||
r = dns_name_apply_idna(s, &buf);
|
||||
log_debug("dns_name_apply_idna: \"%s\" → %d/\"%s\" (expected %d/\"%s\")",
|
||||
s, r, strnull(buf), expected, strnull(result));
|
||||
|
||||
assert_se(r == expected);
|
||||
if (expected == 1)
|
||||
assert_se(dns_name_equal(buf, result) == 1);
|
||||
}
|
||||
|
||||
static void test_dns_name_apply_idna(void) {
|
||||
test_dns_name_apply_idna_one("", "");
|
||||
test_dns_name_apply_idna_one("foo", "foo");
|
||||
test_dns_name_apply_idna_one("foo.", "foo");
|
||||
test_dns_name_apply_idna_one("foo.bar", "foo.bar");
|
||||
test_dns_name_apply_idna_one("foo.bar.", "foo.bar");
|
||||
test_dns_name_apply_idna_one("föö", "xn--f-1gaa");
|
||||
test_dns_name_apply_idna_one("föö.", "xn--f-1gaa");
|
||||
test_dns_name_apply_idna_one("föö.bär", "xn--f-1gaa.xn--br-via");
|
||||
test_dns_name_apply_idna_one("föö.bär.", "xn--f-1gaa.xn--br-via");
|
||||
#if defined HAVE_LIBIDN2 || defined HAVE_LIBIDN
|
||||
const int ret = 1;
|
||||
#else
|
||||
const int ret = 0;
|
||||
#endif
|
||||
|
||||
/* IDNA2008 forbids names with hyphens in third and fourth positions
|
||||
* (https://tools.ietf.org/html/rfc5891#section-4.2.3.1).
|
||||
* IDNA2003 does not have this restriction
|
||||
* (https://tools.ietf.org/html/rfc3490#section-5).
|
||||
* This means that when using libidn we will transform and test more
|
||||
* labels. If registrars follow IDNA2008 we'll just be performing a
|
||||
* useless lookup.
|
||||
*/
|
||||
#if defined HAVE_LIBIDN
|
||||
const int ret2 = 1;
|
||||
#else
|
||||
const int ret2 = 0;
|
||||
#endif
|
||||
|
||||
test_dns_name_apply_idna_one("", ret, "");
|
||||
test_dns_name_apply_idna_one("foo", ret, "foo");
|
||||
test_dns_name_apply_idna_one("foo.", ret, "foo");
|
||||
test_dns_name_apply_idna_one("foo.bar", ret, "foo.bar");
|
||||
test_dns_name_apply_idna_one("foo.bar.", ret, "foo.bar");
|
||||
test_dns_name_apply_idna_one("föö", ret, "xn--f-1gaa");
|
||||
test_dns_name_apply_idna_one("föö.", ret, "xn--f-1gaa");
|
||||
test_dns_name_apply_idna_one("föö.bär", ret, "xn--f-1gaa.xn--br-via");
|
||||
test_dns_name_apply_idna_one("föö.bär.", ret, "xn--f-1gaa.xn--br-via");
|
||||
test_dns_name_apply_idna_one("xn--f-1gaa.xn--br-via", ret, "xn--f-1gaa.xn--br-via");
|
||||
|
||||
test_dns_name_apply_idna_one("r3---sn-ab5l6ne7.googlevideo.com", ret2,
|
||||
ret2 ? "r3---sn-ab5l6ne7.googlevideo.com" : "");
|
||||
}
|
||||
|
||||
static void test_dns_name_is_valid_or_address(void) {
|
||||
|
@ -640,6 +669,9 @@ static void test_dns_name_is_valid_or_address(void) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
test_dns_label_unescape();
|
||||
test_dns_label_unescape_suffix();
|
||||
|
|
Loading…
Reference in a new issue