summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--README2
-rw-r--r--configure.ac33
-rw-r--r--meson.build21
-rw-r--r--meson_options.txt2
-rw-r--r--src/basic/build.h7
-rw-r--r--src/resolve/resolved-dns-question.c8
-rw-r--r--src/resolve/resolved-manager.c32
-rw-r--r--src/resolve/test-dnssec-complex.c2
-rw-r--r--src/shared/dns-domain.c38
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/test/test-dns-domain.c2
12 files changed, 119 insertions, 34 deletions
diff --git a/Makefile.am b/Makefile.am
index 1284d14e52..e6b573587d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1137,6 +1137,7 @@ libshared_la_CFLAGS = \
$(AM_CFLAGS) \
$(ACL_CFLAGS) \
$(LIBIDN_CFLAGS) \
+ $(LIBIDN2_CFLAGS) \
$(SECCOMP_CFLAGS) \
$(BLKID_CFLAGS) \
$(LIBCRYPTSETUP_CFLAGS)
@@ -1148,6 +1149,7 @@ libshared_la_LIBADD = \
libudev-internal.la \
$(ACL_LIBS) \
$(LIBIDN_LIBS) \
+ $(LIBIDN2_LIBS) \
$(SECCOMP_LIBS) \
$(BLKID_LIBS) \
$(LIBCRYPTSETUP_LIBS)
@@ -1171,6 +1173,7 @@ libsystemd_shared_la_CFLAGS = \
$(libudev_internal_la_CFLAGS) \
$(ACL_CFLAGS) \
$(LIBIDN_CFLAGS) \
+ $(LIBIDN2_CFLAGS) \
$(SECCOMP_CFLAGS) \
$(BLKID_CFLAGS) \
$(LIBCRYPTSETUP_CFLAGS) \
@@ -1185,6 +1188,7 @@ libsystemd_shared_la_LIBADD = \
$(libudev_internal_la_LIBADD) \
$(ACL_LIBS) \
$(LIBIDN_LIBS) \
+ $(LIBIDN2_LIBS) \
$(SECCOMP_LIBS) \
$(BLKID_LIBS) \
$(LIBCRYPTSETUP_LIBS)
diff --git a/README b/README
index d7477510a9..427190aa87 100644
--- a/README
+++ b/README
@@ -142,7 +142,7 @@ REQUIREMENTS:
libqrencode (optional)
libmicrohttpd (optional)
libpython (optional)
- libidn (optional)
+ libidn2 or libidn (optional)
elfutils >= 158 (optional)
make, gcc, and similar tools
diff --git a/configure.ac b/configure.ac
index f59f3faf38..a934fe85c9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1015,16 +1015,32 @@ AM_CONDITIONAL(HAVE_LIBCURL, [test "$have_libcurl" = "yes"])
AM_CONDITIONAL(HAVE_REMOTE, [test "$have_microhttpd" = "yes" -o "$have_libcurl" = "yes"])
# ------------------------------------------------------------------------------
+have_libidn2=no
+AC_ARG_ENABLE(libidn2, AS_HELP_STRING([--disable-libidn2], [disable optional LIBIDN2 support]))
+if test "x$enable_libidn2" != "xno"; then
+ PKG_CHECK_MODULES(LIBIDN2, [libidn2 >= 2.0.0],
+ [AC_DEFINE(HAVE_LIBIDN2, 1, [Define if libidn2 is available])
+ have_libidn2=yes
+ M4_DEFINES="$M4_DEFINES -DHAVE_LIBIDN2"],
+ [have_libidn2=no])
+ if test "x$have_libidn2" = "xno" -a "x$enable_libidn2" = "xyes"; then
+ AC_MSG_ERROR([*** libidn2 support requested but libraries not found])
+ fi
+fi
+AM_CONDITIONAL(HAVE_LIBIDN2, [test "$have_libidn2" = "yes"])
+
have_libidn=no
AC_ARG_ENABLE(libidn, AS_HELP_STRING([--disable-libidn], [disable optional LIBIDN support]))
-if test "x$enable_libidn" != "xno"; then
- PKG_CHECK_MODULES(LIBIDN, [libidn],
- [AC_DEFINE(HAVE_LIBIDN, 1, [Define if libidn is available])
- have_libidn=yes
- M4_DEFINES="$M4_DEFINES -DHAVE_LIBIDN"],
- [have_libidn=no])
- if test "x$have_libidn" = "xno" -a "x$enable_libidn" = "xyes"; then
- AC_MSG_ERROR([*** libidn support requested but libraries not found])
+if test "$have_libidn2" != "yes"; then
+ if test "x$enable_libidn" != "xno"; then
+ PKG_CHECK_MODULES(LIBIDN, [libidn],
+ [AC_DEFINE(HAVE_LIBIDN, 1, [Define if libidn is available])
+ have_libidn=yes
+ M4_DEFINES="$M4_DEFINES -DHAVE_LIBIDN"],
+ [have_libidn=no])
+ if test "x$have_libidn" = "xno" -a "x$enable_libidn" = "xyes"; then
+ AC_MSG_ERROR([*** libidn support requested but libraries not found])
+ fi
fi
fi
AM_CONDITIONAL(HAVE_LIBIDN, [test "$have_libidn" = "yes"])
@@ -1715,6 +1731,7 @@ AC_MSG_RESULT([
MICROHTTPD: ${have_microhttpd}
GNUTLS: ${have_gnutls}
libcurl: ${have_libcurl}
+ libidn2: ${have_libidn2}
libidn: ${have_libidn}
libiptc: ${have_libiptc}
ELFUTILS: ${have_elfutils}
diff --git a/meson.build b/meson.build
index 14a20530d4..2067dfe604 100644
--- a/meson.build
+++ b/meson.build
@@ -791,15 +791,29 @@ else
endif
want_libidn = get_option('libidn')
-if want_libidn != 'false'
+want_libidn2 = get_option('libidn2')
+if want_libidn == 'true' and want_libidn2 == 'true'
+ error('libidn and libidn2 cannot be requested simultaneously')
+endif
+
+if want_libidn2 != 'false' and want_libidn != 'true'
+ libidn = dependency('libidn2',
+ required : want_libidn2 == 'true')
+ # libidn is used for both libidn and libidn2 objects
+ if libidn.found()
+ conf.set('HAVE_LIBIDN2', true)
+ m4_defines += ['-DHAVE_LIBIDN2']
+ endif
+else
+ libidn = []
+endif
+if not conf.get('HAVE_LIBIDN2', false) and want_libidn != 'false'
libidn = dependency('libidn',
required : want_libidn == 'true')
if libidn.found()
conf.set('HAVE_LIBIDN', true)
m4_defines += ['-DHAVE_LIBIDN']
endif
-else
- libidn = []
endif
want_libiptc = get_option('libiptc')
@@ -2428,6 +2442,7 @@ foreach tuple : [
['microhttpd'],
['gnutls'],
['libcurl'],
+ ['libidn2'],
['libidn'],
['libiptc'],
['elfutils'],
diff --git a/meson_options.txt b/meson_options.txt
index 4e99b25e63..e2e3b7bb4c 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -195,6 +195,8 @@ option('libcryptsetup', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libcryptsetup support')
option('libcurl', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libcurl support')
+option('libidn2', type : 'combo', choices : ['auto', 'true', 'false'],
+ description : 'libidn2 support')
option('libidn', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libidn support')
option('libiptc', type : 'combo', choices : ['auto', 'true', 'false'],
diff --git a/src/basic/build.h b/src/basic/build.h
index 91312bd2a3..3223915da6 100644
--- a/src/basic/build.h
+++ b/src/basic/build.h
@@ -127,6 +127,12 @@
#define _KMOD_FEATURE_ "-KMOD"
#endif
+#ifdef HAVE_LIBIDN2
+#define _IDN2_FEATURE_ "+IDN2"
+#else
+#define _IDN2_FEATURE_ "-IDN2"
+#endif
+
#ifdef HAVE_LIBIDN
#define _IDN_FEATURE_ "+IDN"
#else
@@ -154,5 +160,6 @@
_BLKID_FEATURE_ " " \
_ELFUTILS_FEATURE_ " " \
_KMOD_FEATURE_ " " \
+ _IDN2_FEATURE_ " " \
_IDN_FEATURE_ " " \
_CGROUP_HIEARCHY_
diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c
index c8b502d1cd..af29f73164 100644
--- a/src/resolve/resolved-dns-question.c
+++ b/src/resolve/resolved-dns-question.c
@@ -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);
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 9db8b8f616..cc9b26d4d5 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -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");
diff --git a/src/resolve/test-dnssec-complex.c b/src/resolve/test-dnssec-complex.c
index 3d7074af11..090b2fac23 100644
--- a/src/resolve/test-dnssec-complex.c
+++ b/src/resolve/test-dnssec-complex.c
@@ -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);
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 33debadb15..40aec3a1ea 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -17,9 +17,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_LIBIDN
-#include <idna.h>
-#include <stringprep.h>
+#if defined(HAVE_LIBIDN2)
+# include <idn2.h>
+#elif defined(HAVE_LIBIDN)
+# include <idna.h>
+# include <stringprep.h>
#endif
#include <endian.h>
@@ -299,8 +301,8 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
return r;
}
-int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
#ifdef HAVE_LIBIDN
+int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
_cleanup_free_ uint32_t *input = NULL;
size_t input_size, l;
const char *p;
@@ -348,13 +350,9 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
decoded[l] = 0;
return (int) l;
-#else
- return 0;
-#endif
}
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-#ifdef HAVE_LIBIDN
size_t input_size, output_size;
_cleanup_free_ uint32_t *input = NULL;
_cleanup_free_ char *result = NULL;
@@ -399,10 +397,8 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
decoded[w] = 0;
return w;
-#else
- return 0;
-#endif
}
+#endif
int dns_name_concat(const char *a, const char *b, char **_ret) {
_cleanup_free_ char *ret = NULL;
@@ -1274,6 +1270,23 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
}
int dns_name_apply_idna(const char *name, char **ret) {
+ /* Return negative on error, 0 if not implemented, positive on success. */
+
+#if defined(HAVE_LIBIDN2)
+ int r;
+
+ assert(name);
+ assert(ret);
+
+ r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) 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))
+ return -ENOSPC;
+ else
+ return -EINVAL;
+#elif defined(HAVE_LIBIDN)
_cleanup_free_ char *buf = NULL;
size_t n = 0, allocated = 0;
bool first = true;
@@ -1323,6 +1336,9 @@ int dns_name_apply_idna(const char *name, char **ret) {
buf = NULL;
return (int) n;
+#else
+ return 0;
+#endif
}
int dns_name_is_valid_or_address(const char *name) {
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 03f160369c..fca025def0 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -51,8 +51,10 @@ static inline int dns_name_parent(const char **name) {
return dns_label_unescape(name, NULL, DNS_LABEL_MAX);
}
+#if defined(HAVE_LIBIDN)
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
+#endif
int dns_name_concat(const char *a, const char *b, char **ret);
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index a7cd8e4b51..d86add94db 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -608,7 +608,7 @@ static void test_dns_name_common_suffix(void) {
}
static void test_dns_name_apply_idna_one(const char *s, const char *result) {
-#ifdef HAVE_LIBIDN
+#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
_cleanup_free_ char *buf = NULL;
assert_se(dns_name_apply_idna(s, &buf) >= 0);
assert_se(dns_name_equal(buf, result) > 0);