resolved: support libidn2 in addition to libidn

libidn2 2.0.0 supports IDNA2008, in contrast to libidn which supports IDNA2003.

https://bugzilla.redhat.com/show_bug.cgi?id=1449145
From that bug report:

Internationalized domain names exist for quite some time (IDNA2003), although
the protocols describing them have evolved in an incompatible way (IDNA2008).
These incompatibilities will prevent applications written for IDNA2003 to
access certain problematic domain names defined with IDNA2008, e.g., faß.de is
translated to domain xn--fa-hia.de with IDNA2008, while in IDNA2003 it is
translated to fass.de domain. That not only causes incompatibility problems,
but may be used as an attack vector to redirect users to different web sites.

v2:
- keep libidn support
- require libidn2 >= 2.0.0
v3:
- keep dns_name_apply_idna caller dumb, and keep the #ifdefs inside of the
  function.
- use both ±IDN and ±IDN2 in the version string
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2017-05-11 14:25:01 -04:00
parent 9bfc0df113
commit 87057e244b
12 changed files with 119 additions and 34 deletions
+4 -4
View File
@@ -309,8 +309,8 @@ 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;
name = buf;
if (r > 0)
name = buf;
}
q = dns_question_new(family == AF_UNSPEC ? 2 : 1);
@@ -422,8 +422,8 @@ int dns_question_new_service(
r = dns_name_apply_idna(domain, &buf);
if (r < 0)
return r;
domain = buf;
if (r > 0)
domain = buf;
}
r = dns_service_join(service, type, domain, &joined);
+27 -5
View File
@@ -21,6 +21,10 @@
#include <poll.h>
#include <sys/ioctl.h>
#ifdef HAVE_LIBIDN2
#include <idn2.h>
#endif
#include "af-list.h"
#include "alloc-util.h"
#include "dirent-util.h"
@@ -324,9 +328,14 @@ static int manager_network_monitor_listen(Manager *m) {
static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
_cleanup_free_ char *h = NULL, *n = NULL;
#if defined(HAVE_LIBIDN2)
_cleanup_free_ char *utf8 = NULL;
#elif defined(HAVE_LIBIDN)
int k;
#endif
char label[DNS_LABEL_MAX];
const char *p;
int r, k;
const char *p, *decoded;
int r;
assert(full_hostname);
assert(llmnr_hostname);
@@ -339,7 +348,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return log_debug_errno(r, "Can't determine system hostname: %m");
p = h;
r = dns_label_unescape(&p, label, sizeof(label));
r = dns_label_unescape(&p, label, sizeof label);
if (r < 0)
return log_error_errno(r, "Failed to unescape host name: %m");
if (r == 0) {
@@ -347,7 +356,16 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return -EINVAL;
}
k = dns_label_undo_idna(label, r, label, sizeof(label));
#if defined(HAVE_LIBIDN2)
r = idn2_to_unicode_8z8z(label, &utf8, 0);
if (r != IDN2_OK)
return log_error("Failed to undo IDNA: %s", idn2_strerror(r));
assert(utf8_is_valid(utf8));
r = strlen(utf8);
decoded = utf8;
#elif defined(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)
@@ -357,8 +375,12 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
log_error("System hostname is not UTF-8 clean.");
return -EINVAL;
}
decoded = label;
#else
decoded = label; /* no decoding */
#endif
r = dns_label_escape_new(label, r, &n);
r = dns_label_escape_new(decoded, r, &n);
if (r < 0)
return log_error_errno(r, "Failed to escape host name: %m");
+1 -1
View File
@@ -218,7 +218,7 @@ int main(int argc, char* argv[]) {
test_hostname_lookup(bus, "poettering.de", AF_INET, NULL);
test_hostname_lookup(bus, "poettering.de", AF_INET6, NULL);
#ifdef HAVE_LIBIDN
#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
/* Unsigned A with IDNA conversion necessary */
test_hostname_lookup(bus, "pöttering.de", AF_UNSPEC, NULL);
test_hostname_lookup(bus, "pöttering.de", AF_INET, NULL);