f505a4
From 3dcf053c775344855bd6476ec4f4bada824cdd41 Mon Sep 17 00:00:00 2001
f505a4
From: Tomas Hozza <thozza@redhat.com>
f505a4
Date: Wed, 23 Sep 2015 14:37:16 +0200
f505a4
Subject: [PATCH] Add support for GNU libidn
f505a4
MIME-Version: 1.0
f505a4
Content-Type: text/plain; charset=UTF-8
f505a4
Content-Transfer-Encoding: 8bit
f505a4
f505a4
Added new configure option:
f505a4
--with-libidn - to enable IDN using GNU libidn
f505a4
f505a4
Renamed configure option:
f505a4
--with-idn to --with-idnkit to make the option usage more clear
f505a4
f505a4
idnkit and libidn support can not be used at the same time.
f505a4
f505a4
Signed-off-by: Tomas Hozza <thozza@redhat.com>
f505a4
(cherry picked from commit 2320443f63b14ff926d0b91b479a48e29bc02376)
f505a4
(cherry picked from commit edab22119f5d2b45a18727a6eb92f11b39ca3e73)
f505a4
f505a4
Add support for libidn2
f505a4
f505a4
Added two new configure options:
f505a4
--with-libidn2 - to enable IDN using GNU libidn2
f505a4
f505a4
idnkit, libidn and libidn2 support can not be used at the same time.
f505a4
f505a4
NOTE: libidn2 does not support punycode back to Unicode
f505a4
characters, so support for this is missing.
f505a4
f505a4
Signed-off-by: Tomas Hozza <thozza@redhat.com>
f505a4
f505a4
Removed iconv, convert directly from locale to ACE
f505a4
f505a4
Fix libidn2 and idnkit origin appending
f505a4
f505a4
Make IDN options in help less different
f505a4
f505a4
Signed-off-by: Petr Menšík <pemensik@redhat.com>
f505a4
(cherry picked from commit 505f673451d9f94488b99f5af0ea042e3f8e0915)
f505a4
(cherry picked from commit 56b66f01c6ae4d9db3a2b8df29af21f43ed65516)
f505a4
f505a4
Remove conversion from locale to utf8 from public API
f505a4
f505a4
Emit fatal failures on locale to ACE encoding
f505a4
f505a4
Separate idnout support, disable it for libidn2 < 2.0
f505a4
f505a4
Add custom path to libidn. Leave default path for multilib support.
f505a4
f505a4
Allow turning off IDN input processing by dig option
f505a4
f505a4
Improve documentation, fix support in host
f505a4
f505a4
Fix configure changes to adjust help text
f505a4
f505a4
Use strlcpy with size guard
f505a4
f505a4
Improve IDN variants choosing. Fix idn2 function name.
f505a4
f505a4
Remove immediate idn_locale_to_ace and idn_ace_to_locale.
f505a4
f505a4
Signed-off-by: Petr Menšík <pemensik@redhat.com>
f505a4
(cherry picked from commit 94757c1545259ec3d7d99f3ba7f9baa9ce58e0d3)
f505a4
(cherry picked from commit 2b031d17592a253297545c6e525019706c17c460)
f505a4
f505a4
Remove support for libidn (IDN 2003)
f505a4
f505a4
Signed-off-by: Petr Menšík <pemensik@redhat.com>
f505a4
(cherry picked from commit 8254cf69d34947713c99839dd5139f326d8e5d43)
f505a4
(cherry picked from commit 9117bbe9a5d637d51ef11c71ff6743e027db5e9e)
f505a4
f505a4
Sanitize IDN initialization
f505a4
f505a4
Signed-off-by: Petr Menšík <pemensik@redhat.com>
f505a4
(cherry picked from commit 29b94bbb04014681afe61c1594b99f6ec30f6b1f)
f505a4
(cherry picked from commit 82914d0a416edb6667e94b54ae828cd0ca8f029b)
f505a4
f505a4
Simplify the libidn2 configure checks
f505a4
f505a4
(cherry picked from commit 76c05a71fcf464d6a638b2d8fab589100850e3f0)
f505a4
(cherry picked from commit c08528682254506f4bcf8155d700eff3ce18b601)
f505a4
f505a4
Add release notes for IDNA2008
f505a4
f505a4
(cherry picked from commit e7590c7528229c7bc761a6c69c33dfb69fbaf82f)
f505a4
(cherry picked from commit 2ff3b664bca0c084326d2eaf75cb3b382fa26108)
f505a4
---
f505a4
 bin/dig/Makefile.in       |   6 +-
f505a4
 bin/dig/dig.c             |  27 +++-
f505a4
 bin/dig/dig.docbook       |  18 ++-
f505a4
 bin/dig/dighost.c         | 304 +++++++++++++++++++++++++++++-----------------
f505a4
 bin/dig/host.c            |  10 +-
f505a4
 bin/dig/include/dig/dig.h |   3 +-
f505a4
 config.h.in               |  11 +-
f505a4
 configure                 | 181 ++++++++++++++++++++++++---
f505a4
 configure.in              |  81 +++++++++---
f505a4
 doc/arm/notes.xml         |  15 +++
f505a4
 10 files changed, 491 insertions(+), 165 deletions(-)
f505a4
f505a4
diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in
f505a4
index 511fdfe86e..d8080e5b30 100644
f505a4
--- a/bin/dig/Makefile.in
f505a4
+++ b/bin/dig/Makefile.in
f505a4
@@ -16,7 +16,7 @@ READLINE_LIB = @READLINE_LIB@
f505a4
 
f505a4
 CINCLUDES =	-I${srcdir}/include ${DNS_INCLUDES} \
f505a4
 		${BIND9_INCLUDES} ${ISC_INCLUDES} \
f505a4
-		${LWRES_INCLUDES} ${ISCCFG_INCLUDES} @DST_OPENSSL_INC@
f505a4
+		${LWRES_INCLUDES} ${ISCCFG_INCLUDES} @LIBIDN2_CFLAGS@ @DST_OPENSSL_INC@
f505a4
 
f505a4
 CDEFINES =	-DVERSION=\"${VERSION}\" @CRYPTO@
f505a4
 CWARNINGS =
f505a4
@@ -38,10 +38,10 @@ DEPLIBS =	${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} \
f505a4
 		${ISCCFGDEPLIBS} ${LWRESDEPLIBS}
f505a4
 
f505a4
 LIBS =		${LWRESLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
f505a4
-		${ISCLIBS} @IDNLIBS@ @LIBS@
f505a4
+		${ISCLIBS} @IDNKIT_LIBS@ @LIBIDN2_LIBS@ @LIBS@
f505a4
 
f505a4
 NOSYMLIBS =	${LWRESLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
f505a4
-		${ISCNOSYMLIBS} @IDNLIBS@ @LIBS@
f505a4
+		${ISCNOSYMLIBS} @IDNKIT_LIBS@ @LIBIDN2_LIBS@ @LIBS@
f505a4
 
f505a4
 SUBDIRS =
f505a4
 
f505a4
diff --git a/bin/dig/dig.c b/bin/dig/dig.c
f505a4
index 2e1ade8bf3..9a1176353e 100644
f505a4
--- a/bin/dig/dig.c
f505a4
+++ b/bin/dig/dig.c
f505a4
@@ -187,7 +187,8 @@ help(void) {
f505a4
 "                 +[no]fail           (Don't try next server on SERVFAIL)\n"
f505a4
 "                 +[no]header-only    (Send query without a question section)\n"
f505a4
 "                 +[no]identify       (ID responders in short answers)\n"
f505a4
-"                 +[no]idnout         (convert IDN response)\n"
f505a4
+"                 +[no]idnin          (Parse IDN names)\n"
f505a4
+"                 +[no]idnout         (Convert IDN response)\n"
f505a4
 "                 +[no]ignore         (Don't revert to TCP for TC responses.)\n"
f505a4
 "                 +[no]keepopen       (Keep the TCP socket open between queries)\n"
f505a4
 "                 +[no]mapped         (Allow mapped IPv4 over IPv6)\n"
f505a4
@@ -1091,12 +1092,28 @@ plus_option(const char *option, isc_boolean_t is_batchfile,
f505a4
 				lookup->identify = state;
f505a4
 				break;
f505a4
 			case 'n':
f505a4
-				FULLCHECK("idnout");
f505a4
-#ifndef WITH_IDN
f505a4
-				fprintf(stderr, ";; IDN support not enabled\n");
f505a4
+				switch (cmd[3]) {
f505a4
+				case 'i':
f505a4
+					FULLCHECK("idnin");
f505a4
+#ifndef WITH_IDN_SUPPORT
f505a4
+					fprintf(stderr, ";; IDN input support"
f505a4
+					        " not enabled\n");
f505a4
+#else
f505a4
+					lookup->idnin = state;
f505a4
+#endif
f505a4
+				break;
f505a4
+				case 'o':
f505a4
+					FULLCHECK("idnout");
f505a4
+#ifndef WITH_IDN_OUT_SUPPORT
f505a4
+					fprintf(stderr, ";; IDN output support"
f505a4
+					        " not enabled\n");
f505a4
 #else
f505a4
-				lookup->idnout = state;
f505a4
+					lookup->idnout = state;
f505a4
 #endif
f505a4
+					break;
f505a4
+				default:
f505a4
+					goto invalid_option;
f505a4
+				}
f505a4
 				break;
f505a4
 			default:
f505a4
 				goto invalid_option;
f505a4
diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook
f505a4
index bee62c6307..da5b7d6515 100644
f505a4
--- a/bin/dig/dig.docbook
f505a4
+++ b/bin/dig/dig.docbook
f505a4
@@ -773,6 +773,17 @@
f505a4
 	  </listitem>
f505a4
 	</varlistentry>
f505a4
 
f505a4
+	<varlistentry>
f505a4
+	  <term><option>+[no]idnin</option></term>
f505a4
+	  <listitem>
f505a4
+	    <para>
f505a4
+	      Process [do not process] IDN domain names on input.
f505a4
+	      This requires IDN SUPPORT to have been enabled at
f505a4
+	      compile time.  The default is to process IDN input.
f505a4
+	    </para>
f505a4
+	  </listitem>
f505a4
+	</varlistentry>
f505a4
+
f505a4
 	<varlistentry>
f505a4
 	  <term><option>+[no]idnout</option></term>
f505a4
 	  <listitem>
f505a4
@@ -1265,10 +1276,9 @@ dig +qr www.isc.org any -x 127.0.0.1 isc.org ns +noqr
f505a4
       <command>dig</command> appropriately converts character encoding of
f505a4
       domain name before sending a request to DNS server or displaying a
f505a4
       reply from the server.
f505a4
-      If you'd like to turn off the IDN support for some reason, defines
f505a4
-      the <envar>IDN_DISABLE</envar> environment variable.
f505a4
-      The IDN support is disabled if the variable is set when
f505a4
-      <command>dig</command> runs.
f505a4
+      If you'd like to turn off the IDN support for some reason, use 
f505a4
+      parameters <parameter>+noidnin</parameter> and
f505a4
+      <parameter>+noidnout</parameter>.
f505a4
     </para>
f505a4
   </refsection>
f505a4
 
f505a4
diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
f505a4
index fdfff399f5..c179b625f1 100644
f505a4
--- a/bin/dig/dighost.c
f505a4
+++ b/bin/dig/dighost.c
f505a4
@@ -21,18 +21,25 @@
f505a4
 #include <unistd.h>
f505a4
 #include <string.h>
f505a4
 #include <limits.h>
f505a4
+#include <errno.h>
f505a4
 
f505a4
 #ifdef HAVE_LOCALE_H
f505a4
 #include <locale.h>
f505a4
 #endif
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+#ifdef WITH_IDNKIT
f505a4
 #include <idn/result.h>
f505a4
 #include <idn/log.h>
f505a4
 #include <idn/resconf.h>
f505a4
 #include <idn/api.h>
f505a4
 #endif
f505a4
 
f505a4
+#ifdef WITH_LIBIDN2
f505a4
+#include <idn2.h>
f505a4
+#endif
f505a4
+#endif /* WITH_IDN_SUPPORT */
f505a4
+
f505a4
 #include <dns/byaddr.h>
f505a4
 #ifdef DIG_SIGCHASE
f505a4
 #include <dns/callbacks.h>
f505a4
@@ -145,18 +152,26 @@ int lookup_counter = 0;
f505a4
 
f505a4
 static char servercookie[256];
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
-static void		initialize_idn(void);
f505a4
-static isc_result_t	output_filter(isc_buffer_t *buffer,
f505a4
-				      unsigned int used_org,
f505a4
-				      isc_boolean_t absolute);
f505a4
-static idn_result_t	append_textname(char *name, const char *origin,
f505a4
-					size_t namesize);
f505a4
-static void		idn_check_result(idn_result_t r, const char *msg);
f505a4
-
f505a4
-#define MAXDLEN		256
f505a4
-int  idnoptions	= 0;
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+static void idn_initialize(void);
f505a4
+static isc_result_t idn_locale_to_ace(const char *from,
f505a4
+		char *to,
f505a4
+		size_t tolen);
f505a4
+#endif /* WITH_IDN_SUPPORT */
f505a4
+
f505a4
+#ifdef WITH_IDN_OUT_SUPPORT
f505a4
+static isc_result_t idn_ace_to_locale(const char *from,
f505a4
+		char *to,
f505a4
+		size_t tolen);
f505a4
+static isc_result_t output_filter(isc_buffer_t *buffer,
f505a4
+		unsigned int used_org,
f505a4
+		isc_boolean_t absolute);
f505a4
+#define MAXDLEN 256
f505a4
+
f505a4
+#ifdef WITH_IDNKIT
f505a4
+int idnoptions = 0;
f505a4
 #endif
f505a4
+#endif /* WITH_IDN_OUT_SUPPORT */
f505a4
 
f505a4
 isc_socket_t *keep = NULL;
f505a4
 isc_sockaddr_t keepaddr;
f505a4
@@ -803,7 +818,12 @@ make_empty_lookup(void) {
f505a4
 	looknew->sendcookie = ISC_FALSE;
f505a4
 	looknew->seenbadcookie = ISC_FALSE;
f505a4
 	looknew->badcookie = ISC_TRUE;
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+	looknew->idnin = ISC_TRUE;
f505a4
+#else
f505a4
+	looknew->idnin = ISC_FALSE;
f505a4
+#endif
f505a4
+#ifdef WITH_IDN_OUT_SUPPORT
f505a4
 	looknew->idnout = ISC_TRUE;
f505a4
 #else
f505a4
 	looknew->idnout = ISC_FALSE;
f505a4
@@ -952,6 +972,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
f505a4
 	}
f505a4
 	looknew->ednsneg = lookold->ednsneg;
f505a4
 	looknew->mapped = lookold->mapped;
f505a4
+	looknew->idnin = lookold->idnin;
f505a4
 	looknew->idnout = lookold->idnout;
f505a4
 #ifdef DIG_SIGCHASE
f505a4
 	looknew->sigchase = lookold->sigchase;
f505a4
@@ -1512,8 +1533,19 @@ setup_system(isc_boolean_t ipv4only, isc_boolean_t ipv6only) {
f505a4
 		copy_server_list(lwconf, &server_list);
f505a4
 	}
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
-	initialize_idn();
f505a4
+#ifdef HAVE_SETLOCALE
f505a4
+	/* Set locale */
f505a4
+	(void)setlocale(LC_ALL, "");
f505a4
+#endif
f505a4
+
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+	idn_initialize();
f505a4
+#endif
f505a4
+
f505a4
+#ifdef WITH_IDN_OUT_SUPPORT
f505a4
+	/* Set domain name -> text post-conversion filter. */
f505a4
+	result = dns_name_settotextfilter(output_filter);
f505a4
+	check_result(result, "dns_name_settotextfilter");
f505a4
 #endif
f505a4
 
f505a4
 	if (keyfile[0] != 0)
f505a4
@@ -2344,12 +2376,13 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 	char store[MXNAME];
f505a4
 	char ecsbuf[20];
f505a4
 	char cookiebuf[256];
f505a4
-#ifdef WITH_IDN
f505a4
-	idn_result_t mr;
f505a4
-	char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME];
f505a4
+	char *origin = NULL;
f505a4
+	char *textname = NULL;
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+	char idn_origin[MXNAME], idn_textname[MXNAME];
f505a4
 #endif
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDN_OUT_SUPPORT
f505a4
 	result = dns_name_settotextfilter(lookup->idnout ?
f505a4
 					  output_filter : NULL);
f505a4
 	check_result(result, "dns_name_settotextfilter");
f505a4
@@ -2382,15 +2415,20 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 	isc_buffer_init(&lookup->onamebuf, lookup->oname_space,
f505a4
 			sizeof(lookup->oname_space));
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
 	/*
f505a4
 	 * We cannot convert `textname' and `origin' separately.
f505a4
 	 * `textname' doesn't contain TLD, but local mapping needs
f505a4
 	 * TLD.
f505a4
 	 */
f505a4
-	mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname,
f505a4
-			    utf8_textname, sizeof(utf8_textname));
f505a4
-	idn_check_result(mr, "convert textname to UTF-8");
f505a4
+	textname = lookup->textname;
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+	if (lookup->idnin) {
f505a4
+		result = idn_locale_to_ace(lookup->textname, idn_textname,
f505a4
+					    sizeof(idn_textname));
f505a4
+		check_result(result, "convert textname to IDN encoding");
f505a4
+		debug("idn_textname: %s", idn_textname);
f505a4
+		textname = idn_textname;
f505a4
+	}
f505a4
 #endif
f505a4
 
f505a4
 	/*
f505a4
@@ -2401,17 +2439,8 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 	 * is TRUE or we got a domain line in the resolv.conf file.
f505a4
 	 */
f505a4
 	if (lookup->new_search) {
f505a4
-#ifdef WITH_IDN
f505a4
-		if ((count_dots(utf8_textname) >= ndots) || !usesearch) {
f505a4
-			lookup->origin = NULL; /* Force abs lookup */
f505a4
-			lookup->done_as_is = ISC_TRUE;
f505a4
-			lookup->need_search = usesearch;
f505a4
-		} else if (lookup->origin == NULL && usesearch) {
f505a4
-			lookup->origin = ISC_LIST_HEAD(search_list);
f505a4
-			lookup->need_search = ISC_FALSE;
f505a4
-		}
f505a4
-#else
f505a4
-		if ((count_dots(lookup->textname) >= ndots) || !usesearch) {
f505a4
+		if ((count_dots(textname) >= ndots) || !usesearch)
f505a4
+		{
f505a4
 			lookup->origin = NULL; /* Force abs lookup */
f505a4
 			lookup->done_as_is = ISC_TRUE;
f505a4
 			lookup->need_search = usesearch;
f505a4
@@ -2419,24 +2448,8 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 			lookup->origin = ISC_LIST_HEAD(search_list);
f505a4
 			lookup->need_search = ISC_FALSE;
f505a4
 		}
f505a4
-#endif
f505a4
 	}
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
-	if (lookup->origin != NULL) {
f505a4
-		mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP,
f505a4
-				    lookup->origin->origin, utf8_origin,
f505a4
-				    sizeof(utf8_origin));
f505a4
-		idn_check_result(mr, "convert origin to UTF-8");
f505a4
-		mr = append_textname(utf8_textname, utf8_origin,
f505a4
-				     sizeof(utf8_textname));
f505a4
-		idn_check_result(mr, "append origin to textname");
f505a4
-	}
f505a4
-	mr = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP |
f505a4
-			    IDN_IDNCONV | IDN_LENCHECK, utf8_textname,
f505a4
-			    idn_textname, sizeof(idn_textname));
f505a4
-	idn_check_result(mr, "convert UTF-8 textname to IDN encoding");
f505a4
-#else
f505a4
 	if (lookup->origin != NULL) {
f505a4
 		debug("trying origin %s", lookup->origin->origin);
f505a4
 		result = dns_message_gettempname(lookup->sendmsg,
f505a4
@@ -2444,8 +2457,18 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 		check_result(result, "dns_message_gettempname");
f505a4
 		dns_name_init(lookup->oname, NULL);
f505a4
 		/* XXX Helper funct to conv char* to name? */
f505a4
-		len = (unsigned int) strlen(lookup->origin->origin);
f505a4
-		isc_buffer_init(&b, lookup->origin->origin, len);
f505a4
+		origin = lookup->origin->origin;
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+		if (lookup->idnin) {
f505a4
+			result = idn_locale_to_ace(lookup->origin->origin,
f505a4
+						idn_origin, sizeof(idn_origin));
f505a4
+			check_result(result, "convert origin to IDN encoding");
f505a4
+			debug("trying idn origin %s", idn_origin);
f505a4
+			origin = idn_origin;
f505a4
+		}
f505a4
+#endif
f505a4
+		len = (unsigned int) strlen(origin);
f505a4
+		isc_buffer_init(&b, origin, len);
f505a4
 		isc_buffer_add(&b, len);
f505a4
 		result = dns_name_fromtext(lookup->oname, &b, dns_rootname,
f505a4
 					   0, &lookup->onamebuf);
f505a4
@@ -2455,7 +2478,7 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 			dns_message_puttempname(lookup->sendmsg,
f505a4
 						&lookup->oname);
f505a4
 			fatal("'%s' is not in legal name syntax (%s)",
f505a4
-			      lookup->origin->origin,
f505a4
+			      origin,
f505a4
 			      isc_result_totext(result));
f505a4
 		}
f505a4
 		if (lookup->trace && lookup->trace_root) {
f505a4
@@ -2466,8 +2489,8 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 
f505a4
 			dns_fixedname_init(&fixed);
f505a4
 			name = dns_fixedname_name(&fixed);
f505a4
-			len = (unsigned int) strlen(lookup->textname);
f505a4
-			isc_buffer_init(&b, lookup->textname, len);
f505a4
+			len = (unsigned int) strlen(textname);
f505a4
+			isc_buffer_init(&b, textname, len);
f505a4
 			isc_buffer_add(&b, len);
f505a4
 			result = dns_name_fromtext(name, &b, NULL, 0, NULL);
f505a4
 			if (result == ISC_R_SUCCESS &&
f505a4
@@ -2492,28 +2515,17 @@ setup_lookup(dig_lookup_t *lookup) {
f505a4
 			}
f505a4
 		}
f505a4
 		dns_message_puttempname(lookup->sendmsg, &lookup->oname);
f505a4
-	} else
f505a4
-#endif
f505a4
-	{
f505a4
+	} else {
f505a4
 		debug("using root origin");
f505a4
 		if (lookup->trace && lookup->trace_root)
f505a4
 			dns_name_clone(dns_rootname, lookup->name);
f505a4
 		else {
f505a4
-#ifdef WITH_IDN
f505a4
-			len = (unsigned int) strlen(idn_textname);
f505a4
-			isc_buffer_init(&b, idn_textname, len);
f505a4
+			len = (unsigned int) strlen(textname);
f505a4
+			isc_buffer_init(&b, textname, len);
f505a4
 			isc_buffer_add(&b, len);
f505a4
 			result = dns_name_fromtext(lookup->name, &b,
f505a4
 						   dns_rootname, 0,
f505a4
 						   &lookup->namebuf);
f505a4
-#else
f505a4
-			len = (unsigned int) strlen(lookup->textname);
f505a4
-			isc_buffer_init(&b, lookup->textname, len);
f505a4
-			isc_buffer_add(&b, len);
f505a4
-			result = dns_name_fromtext(lookup->name, &b,
f505a4
-						   dns_rootname, 0,
f505a4
-						   &lookup->namebuf);
f505a4
-#endif
f505a4
 		}
f505a4
 		if (result != ISC_R_SUCCESS) {
f505a4
 			dns_message_puttempname(lookup->sendmsg,
f505a4
@@ -4512,7 +4524,7 @@ destroy_libs(void) {
f505a4
 	void * ptr;
f505a4
 	dig_message_t *chase_msg;
f505a4
 #endif
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
 	isc_result_t result;
f505a4
 #endif
f505a4
 
f505a4
@@ -4549,7 +4561,7 @@ destroy_libs(void) {
f505a4
 
f505a4
 	clear_searchlist();
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
 	result = dns_name_settotextfilter(NULL);
f505a4
 	check_result(result, "dns_name_settotextfilter");
f505a4
 #endif
f505a4
@@ -4633,27 +4645,7 @@ destroy_libs(void) {
f505a4
 		isc_mem_destroy(&mctx);
f505a4
 }
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
-static void
f505a4
-initialize_idn(void) {
f505a4
-	idn_result_t r;
f505a4
-	isc_result_t result;
f505a4
-
f505a4
-#ifdef HAVE_SETLOCALE
f505a4
-	/* Set locale */
f505a4
-	(void)setlocale(LC_ALL, "");
f505a4
-#endif
f505a4
-	/* Create configuration context. */
f505a4
-	r = idn_nameinit(1);
f505a4
-	if (r != idn_success)
f505a4
-		fatal("idn api initialization failed: %s",
f505a4
-		      idn_result_tostring(r));
f505a4
-
f505a4
-	/* Set domain name -> text post-conversion filter. */
f505a4
-	result = dns_name_settotextfilter(output_filter);
f505a4
-	check_result(result, "dns_name_settotextfilter");
f505a4
-}
f505a4
-
f505a4
+#ifdef WITH_IDN_OUT_SUPPORT
f505a4
 static isc_result_t
f505a4
 output_filter(isc_buffer_t *buffer, unsigned int used_org,
f505a4
 	      isc_boolean_t absolute)
f505a4
@@ -4661,6 +4653,7 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org,
f505a4
 	char tmp1[MAXDLEN], tmp2[MAXDLEN];
f505a4
 	size_t fromlen, tolen;
f505a4
 	isc_boolean_t end_with_dot;
f505a4
+	isc_result_t result;
f505a4
 
f505a4
 	/*
f505a4
 	 * Copy contents of 'buffer' to 'tmp1', supply trailing dot
f505a4
@@ -4669,6 +4662,7 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org,
f505a4
 	fromlen = isc_buffer_usedlength(buffer) - used_org;
f505a4
 	if (fromlen >= MAXDLEN)
f505a4
 		return (ISC_R_SUCCESS);
f505a4
+
f505a4
 	memmove(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen);
f505a4
 	end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE;
f505a4
 	if (absolute && !end_with_dot) {
f505a4
@@ -4677,13 +4671,16 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org,
f505a4
 			return (ISC_R_SUCCESS);
f505a4
 		tmp1[fromlen - 1] = '.';
f505a4
 	}
f505a4
+
f505a4
 	tmp1[fromlen] = '\0';
f505a4
 
f505a4
 	/*
f505a4
 	 * Convert contents of 'tmp1' to local encoding.
f505a4
 	 */
f505a4
-	if (idn_decodename(IDN_DECODE_APP, tmp1, tmp2, MAXDLEN) != idn_success)
f505a4
+	result = idn_ace_to_locale(tmp1, tmp2, sizeof(tmp2));
f505a4
+	if (result != ISC_R_SUCCESS) {
f505a4
 		return (ISC_R_SUCCESS);
f505a4
+	}
f505a4
 	strlcpy(tmp1, tmp2, MAXDLEN);
f505a4
 
f505a4
 	/*
f505a4
@@ -4703,35 +4700,118 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org,
f505a4
 
f505a4
 	return (ISC_R_SUCCESS);
f505a4
 }
f505a4
+#endif
f505a4
 
f505a4
-static idn_result_t
f505a4
-append_textname(char *name, const char *origin, size_t namesize) {
f505a4
-	size_t namelen = strlen(name);
f505a4
-	size_t originlen = strlen(origin);
f505a4
+#ifdef WITH_IDN_SUPPORT
f505a4
+#ifdef WITH_IDNKIT
f505a4
+static void
f505a4
+idnkit_check_result(idn_result_t result, const char *msg) {
f505a4
+	if (result != idn_success) {
f505a4
+		fatal("%s: %s", msg, idn_result_tostring(result));
f505a4
+	}
f505a4
+}
f505a4
+
f505a4
+static void
f505a4
+idn_initialize(void) {
f505a4
+	idn_result_t result;
f505a4
 
f505a4
-	/* Already absolute? */
f505a4
-	if (namelen > 0 && name[namelen - 1] == '.')
f505a4
-		return (idn_success);
f505a4
+	/* Create configuration context. */
f505a4
+	result = idn_nameinit(1);
f505a4
+	idnkit_check_result(result, "idnkit api initialization failed");
f505a4
+	return (ISC_R_SUCCESS);
f505a4
+}
f505a4
 
f505a4
-	/* Append dot and origin */
f505a4
+static isc_result_t
f505a4
+idn_locale_to_ace(const char *from, char *to, size_t tolen) {
f505a4
+	char utf8_textname[MXNAME];
f505a4
+	idn_result_t result;
f505a4
+
f505a4
+	result = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, from,
f505a4
+	                        utf8_textname, sizeof(utf8_textname));
f505a4
+	idnkit_check_result(result, "idnkit idn_encodename to utf8 failed");
f505a4
+
f505a4
+	result = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP |
f505a4
+		                IDN_IDNCONV | IDN_LENCHECK,
f505a4
+		                utf8_textname, to, tolen);
f505a4
+	idnkit_check_result(result, "idnkit idn_encodename to idn failed");
f505a4
+	return (ISC_R_SUCCESS);
f505a4
+}
f505a4
 
f505a4
-	if (namelen + 1 + originlen >= namesize)
f505a4
-		return (idn_buffer_overflow);
f505a4
+static isc_result_t
f505a4
+idn_ace_to_locale(const char *from, char *to, size_t tolen) {
f505a4
+	idn_result_t result;
f505a4
 
f505a4
-	if (*origin != '.')
f505a4
-		name[namelen++] = '.';
f505a4
-	(void)strlcpy(name + namelen, origin, namesize - namelen);
f505a4
-	return (idn_success);
f505a4
+	result = idn_decodename(IDN_DECODE_APP, from, to, tolen);
f505a4
+	if (result != idn_success) {
f505a4
+		debug("idnkit idn_decodename failed: %s",
f505a4
+		      idn_result_tostring(result));
f505a4
+		return (ISC_R_FAILURE);
f505a4
+	}
f505a4
+	return (ISC_R_SUCCESS);
f505a4
 }
f505a4
+#endif /* WITH_IDNKIT */
f505a4
 
f505a4
+#ifdef WITH_LIBIDN2
f505a4
 static void
f505a4
-idn_check_result(idn_result_t r, const char *msg) {
f505a4
-	if (r != idn_success) {
f505a4
-		exitcode = 1;
f505a4
-		fatal("%s: %s", msg, idn_result_tostring(r));
f505a4
+idn_initialize(void) {
f505a4
+}
f505a4
+
f505a4
+static isc_result_t
f505a4
+idn_locale_to_ace(const char *from, char *to, size_t tolen) {
f505a4
+	int res;
f505a4
+	char *tmp_str = NULL;
f505a4
+
f505a4
+	res = idn2_lookup_ul(from, &tmp_str, IDN2_NONTRANSITIONAL);
f505a4
+	if (res == IDN2_DISALLOWED)
f505a4
+		res = idn2_lookup_ul(from, &tmp_str, IDN2_TRANSITIONAL);
f505a4
+
f505a4
+	if (res == IDN2_OK) {
f505a4
+		/* check the length */
f505a4
+		if (strlen(tmp_str) >= tolen) {
f505a4
+			debug("ACE string is too long");
f505a4
+			idn2_free(tmp_str);
f505a4
+			return ISC_R_NOSPACE;
f505a4
+		}
f505a4
+
f505a4
+		(void) strlcpy(to, tmp_str, tolen);
f505a4
+		idn2_free(tmp_str);
f505a4
+		return ISC_R_SUCCESS;
f505a4
 	}
f505a4
+
f505a4
+	fatal("idn2_lookup_ul failed: %s", idn2_strerror(res));
f505a4
+	return ISC_R_FAILURE;
f505a4
+}
f505a4
+
f505a4
+#ifdef WITH_IDN_OUT_SUPPORT
f505a4
+static isc_result_t
f505a4
+idn_ace_to_locale(const char *from, char *to, size_t tolen) {
f505a4
+	int res;
f505a4
+	char *tmp_str = NULL;
f505a4
+
f505a4
+	res = idn2_to_unicode_8zlz(from, &tmp_str,
f505a4
+			       IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT);
f505a4
+
f505a4
+	if (res == IDN2_OK) {
f505a4
+		/* check the length */
f505a4
+		if (strlen(tmp_str) >= tolen) {
f505a4
+			debug("encoded ASC string is too long");
f505a4
+			idn2_free(tmp_str);
f505a4
+			return ISC_R_FAILURE;
f505a4
+		}
f505a4
+
f505a4
+		(void) strncpy(to, tmp_str, tolen);
f505a4
+		free(tmp_str);
f505a4
+		return ISC_R_SUCCESS;
f505a4
+	} else {
f505a4
+		debug("idn2_to_unicode_8zlz failed: %s",
f505a4
+		      idn2_strerror(res));
f505a4
+	}
f505a4
+
f505a4
+	return ISC_R_FAILURE;
f505a4
 }
f505a4
-#endif /* WITH_IDN */
f505a4
+#endif /* WITH_IDN_OUT_SUPPORT */
f505a4
+#endif /* WITH_LIBIDN2 */
f505a4
+#endif /* WITH_IDN_SUPPORT */
f505a4
 
f505a4
 #ifdef DIG_SIGCHASE
f505a4
 void
f505a4
diff --git a/bin/dig/host.c b/bin/dig/host.c
f505a4
index f9e5b08962..f16483827a 100644
f505a4
--- a/bin/dig/host.c
f505a4
+++ b/bin/dig/host.c
f505a4
@@ -16,7 +16,7 @@
f505a4
 #include <locale.h>
f505a4
 #endif
f505a4
 
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDNKIT
f505a4
 #include <idn/result.h>
f505a4
 #include <idn/log.h>
f505a4
 #include <idn/resconf.h>
f505a4
@@ -720,7 +720,7 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
f505a4
 			    lookup->rdtype != dns_rdatatype_axfr)
f505a4
 				lookup->rdtype = rdtype;
f505a4
 			lookup->rdtypeset = ISC_TRUE;
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDNKIT
f505a4
 			idnoptions = 0;
f505a4
 #endif
f505a4
 			if (rdtype == dns_rdatatype_axfr) {
f505a4
@@ -735,7 +735,7 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
f505a4
 			} else if (rdtype == dns_rdatatype_any) {
f505a4
 				if (!lookup->tcp_mode_set)
f505a4
 					lookup->tcp_mode = ISC_TRUE;
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDNKIT
f505a4
 			} else if (rdtype == dns_rdatatype_a ||
f505a4
 				   rdtype == dns_rdatatype_aaaa ||
f505a4
 				   rdtype == dns_rdatatype_mx) {
f505a4
@@ -767,7 +767,7 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
f505a4
 			if (!lookup->rdtypeset ||
f505a4
 			    lookup->rdtype != dns_rdatatype_axfr)
f505a4
 				lookup->rdtype = dns_rdatatype_any;
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDNKIT
f505a4
 			idnoptions = 0;
f505a4
 #endif
f505a4
 			list_type = dns_rdatatype_any;
f505a4
@@ -881,7 +881,7 @@ main(int argc, char **argv) {
f505a4
 	ISC_LIST_INIT(search_list);
f505a4
 
f505a4
 	fatalexit = 1;
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDNKIT
f505a4
 	idnoptions = IDN_ASCCHECK;
f505a4
 #endif
f505a4
 
f505a4
diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h
f505a4
index 2c7a5aeaa8..446ee027af 100644
f505a4
--- a/bin/dig/include/dig/dig.h
f505a4
+++ b/bin/dig/include/dig/dig.h
f505a4
@@ -130,6 +130,7 @@ struct dig_lookup {
f505a4
 		ednsneg,
f505a4
 		mapped,
f505a4
 		print_unknown_format,
f505a4
+		idnin,
f505a4
 		idnout;
f505a4
 #ifdef DIG_SIGCHASE
f505a4
 isc_boolean_t	sigchase;
f505a4
@@ -292,7 +293,7 @@ extern char *progname;
f505a4
 extern int tries;
f505a4
 extern int fatalexit;
f505a4
 extern isc_boolean_t verbose;
f505a4
-#ifdef WITH_IDN
f505a4
+#ifdef WITH_IDNKIT
f505a4
 extern int idnoptions;
f505a4
 #endif
f505a4
 
f505a4
diff --git a/config.h.in b/config.h.in
f505a4
index 29cdb07a50..cd798c288d 100644
f505a4
--- a/config.h.in
f505a4
+++ b/config.h.in
f505a4
@@ -596,7 +596,16 @@ int sigwait(const unsigned int *set, int *sig);
f505a4
 #undef WANT_QUERYTRACE
f505a4
 
f505a4
 /* define if idnkit support is to be included. */
f505a4
-#undef WITH_IDN
f505a4
+#undef WITH_IDNKIT
f505a4
+
f505a4
+/* define if IDN output support is to be included. */
f505a4
+#undef WITH_IDN_OUT_SUPPORT
f505a4
+
f505a4
+/* define if IDN input support is to be included. */
f505a4
+#undef WITH_IDN_SUPPORT
f505a4
+
f505a4
+/* define if libidn2 support is to be included. */
f505a4
+#undef WITH_LIBIDN2
f505a4
 
f505a4
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
f505a4
    significant byte first (like Motorola and SPARC, unlike Intel). */
f505a4
diff --git a/configure b/configure
f505a4
index 5ae413202f..ce9f393170 100755
f505a4
--- a/configure
f505a4
+++ b/configure
f505a4
@@ -682,7 +682,9 @@ UNITTESTS
f505a4
 ATFLIBS
f505a4
 ATFBIN
f505a4
 ATFBUILD
f505a4
-IDNLIBS
f505a4
+LIBIDN2_LIBS
f505a4
+LIBIDN2_CFLAGS
f505a4
+IDNKIT_LIBS
f505a4
 XSLT_DBLATEX_FASTBOOK
f505a4
 XSLT_DBLATEX_STYLE
f505a4
 XSLT_DOCBOOK_MAKETOC_XHTML
f505a4
@@ -1066,10 +1068,11 @@ enable_dnstap
f505a4
 with_protobuf_c
f505a4
 with_libfstrm
f505a4
 with_docbook_xsl
f505a4
-with_idn
f505a4
+with_idnkit
f505a4
 with_libiconv
f505a4
 with_iconv
f505a4
 with_idnlib
f505a4
+with_libidn2
f505a4
 with_atf
f505a4
 with_tuning
f505a4
 enable_querytrace
f505a4
@@ -1794,10 +1797,11 @@ Optional Packages:
f505a4
   --with-protobuf-c=path  Path where protobuf-c is installed, for dnstap
f505a4
   --with-libfstrm=path    Path where libfstrm is installed, for dnstap
f505a4
   --with-docbook-xsl=PATH specify path for Docbook-XSL stylesheets
f505a4
-  --with-idn=MPREFIX      enable IDN support using idnkit [default PREFIX]
f505a4
+  --with-idnkit=PATH      enable IDN support using idnkit [yes|no|path]
f505a4
   --with-libiconv=IPREFIX GNU libiconv are in IPREFIX [default PREFIX]
f505a4
   --with-iconv=LIBSPEC    specify iconv library [default -liconv]
f505a4
   --with-idnlib=ARG       specify libidnkit
f505a4
+  --with-libidn2=PATH     enable IDN support using GNU libidn2 [yes|no|path]
f505a4
   --with-atf              support Automated Test Framework
f505a4
   --with-tuning=ARG       Specify server tuning (large or default)
f505a4
   --with-dlopen=ARG       support dynamically loadable DLZ drivers
f505a4
@@ -22755,28 +22759,28 @@ fi
f505a4
 
f505a4
 
f505a4
 #
f505a4
-# IDN support
f505a4
+# IDN support using idnkit
f505a4
 #
f505a4
 
f505a4
-# Check whether --with-idn was given.
f505a4
-if test "${with_idn+set}" = set; then :
f505a4
-  withval=$with_idn; use_idn="$withval"
f505a4
+# Check whether --with-idnkit was given.
f505a4
+if test "${with_idnkit+set}" = set; then :
f505a4
+  withval=$with_idnkit; use_idnkit="$withval"
f505a4
 else
f505a4
-  use_idn="no"
f505a4
+  use_idnkit="no"
f505a4
 fi
f505a4
 
f505a4
-case "$use_idn" in
f505a4
+case "$use_idnkit" in
f505a4
 yes)
f505a4
 	if test X$prefix = XNONE ; then
f505a4
-		idn_path=/usr/local
f505a4
+		idnkit_path=/usr/local
f505a4
 	else
f505a4
-		idn_path=$prefix
f505a4
+		idnkit_path=$prefix
f505a4
 	fi
f505a4
 	;;
f505a4
 no)
f505a4
 	;;
f505a4
 *)
f505a4
-	idn_path="$use_idn"
f505a4
+	idnkit_path="$use_idnkit"
f505a4
 	;;
f505a4
 esac
f505a4
 
f505a4
@@ -22833,20 +22837,161 @@ if test "yes" = "$idnlib"; then
f505a4
 	as_fn_error $? "You must specify ARG for --with-idnlib." "$LINENO" 5
f505a4
 fi
f505a4
 
f505a4
-IDNLIBS=
f505a4
-if test "no" != "$use_idn"; then
f505a4
+IDNKIT_LIBS=
f505a4
+if test "no" != "$use_idnkit"; then
f505a4
 
f505a4
-$as_echo "#define WITH_IDN 1" >>confdefs.h
f505a4
+$as_echo "#define WITH_IDNKIT 1" >>confdefs.h
f505a4
 
f505a4
-	STD_CINCLUDES="$STD_CINCLUDES -I$idn_path/include"
f505a4
+	STD_CINCLUDES="$STD_CINCLUDES -I$idnkit_path/include"
f505a4
 	if test "no" != "$idnlib"; then
f505a4
-		IDNLIBS="$idnlib $iconvlib"
f505a4
+		IDNKIT_LIBS="$idnlib $iconvlib"
f505a4
 	else
f505a4
-		IDNLIBS="-L$idn_path/lib -lidnkit $iconvlib"
f505a4
+		IDNKIT_LIBS="-L$idnkit_path/lib -lidnkit $iconvlib"
f505a4
 	fi
f505a4
 fi
f505a4
 
f505a4
 
f505a4
+#
f505a4
+# IDN support using libidn2
f505a4
+#
f505a4
+
f505a4
+LIBIDN2_CFLAGS=
f505a4
+LIBIDN2_LIBS=
f505a4
+
f505a4
+# Check whether --with-libidn2 was given.
f505a4
+if test "${with_libidn2+set}" = set; then :
f505a4
+  withval=$with_libidn2; use_libidn2="$withval"
f505a4
+else
f505a4
+  use_libidn2="no"
f505a4
+fi
f505a4
+
f505a4
+case $use_libidn2 in #(
f505a4
+  no) :
f505a4
+    : ;; #(
f505a4
+  yes) :
f505a4
+
f505a4
+	    LIBIDN2_LIBS="-lidn2"
f505a4
+	 ;; #(
f505a4
+  *) :
f505a4
+
f505a4
+	    LIBIDN2_CFLAGS="-I$use_libidn2/include"
f505a4
+	    LIBIDN2_LIBS="-L$use_libidn2/lib -lidn2"
f505a4
+	 ;; #(
f505a4
+  *) :
f505a4
+     ;;
f505a4
+esac
f505a4
+
f505a4
+if test "$use_libidn2" != "no"; then :
f505a4
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing idn2_to_ascii_8z" >&5
f505a4
+$as_echo_n "checking for library containing idn2_to_ascii_8z... " >&6; }
f505a4
+if ${ac_cv_search_idn2_to_ascii_8z+:} false; then :
f505a4
+  $as_echo_n "(cached) " >&6
f505a4
+else
f505a4
+  ac_func_search_save_LIBS=$LIBS
f505a4
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
f505a4
+/* end confdefs.h.  */
f505a4
+
f505a4
+/* Override any GCC internal prototype to avoid an error.
f505a4
+   Use char because int might match the return type of a GCC
f505a4
+   builtin and then its argument prototype would still apply.  */
f505a4
+#ifdef __cplusplus
f505a4
+extern "C"
f505a4
+#endif
f505a4
+char idn2_to_ascii_8z ();
f505a4
+int
f505a4
+main ()
f505a4
+{
f505a4
+return idn2_to_ascii_8z ();
f505a4
+  ;
f505a4
+  return 0;
f505a4
+}
f505a4
+_ACEOF
f505a4
+for ac_lib in '' idn2; do
f505a4
+  if test -z "$ac_lib"; then
f505a4
+    ac_res="none required"
f505a4
+  else
f505a4
+    ac_res=-l$ac_lib
f505a4
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
f505a4
+  fi
f505a4
+  if ac_fn_c_try_link "$LINENO"; then :
f505a4
+  ac_cv_search_idn2_to_ascii_8z=$ac_res
f505a4
+fi
f505a4
+rm -f core conftest.err conftest.$ac_objext \
f505a4
+    conftest$ac_exeext
f505a4
+  if ${ac_cv_search_idn2_to_ascii_8z+:} false; then :
f505a4
+  break
f505a4
+fi
f505a4
+done
f505a4
+if ${ac_cv_search_idn2_to_ascii_8z+:} false; then :
f505a4
+
f505a4
+else
f505a4
+  ac_cv_search_idn2_to_ascii_8z=no
f505a4
+fi
f505a4
+rm conftest.$ac_ext
f505a4
+LIBS=$ac_func_search_save_LIBS
f505a4
+fi
f505a4
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_idn2_to_ascii_8z" >&5
f505a4
+$as_echo "$ac_cv_search_idn2_to_ascii_8z" >&6; }
f505a4
+ac_res=$ac_cv_search_idn2_to_ascii_8z
f505a4
+if test "$ac_res" != no; then :
f505a4
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
f505a4
+
f505a4
+$as_echo "#define WITH_LIBIDN2 1" >>confdefs.h
f505a4
+
f505a4
+else
f505a4
+  as_fn_error $? "libidn2 requested, but not found" "$LINENO" 5
f505a4
+fi
f505a4
+
f505a4
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libidn2 supports idn2_to_unicode_8zlz" >&5
f505a4
+$as_echo_n "checking whether libidn2 supports idn2_to_unicode_8zlz... " >&6; }
f505a4
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
f505a4
+/* end confdefs.h.  */
f505a4
+#include <idn2.h>
f505a4
+int
f505a4
+main ()
f505a4
+{
f505a4
+idn2_to_unicode_8zlz(".", NULL, IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT);
f505a4
+  ;
f505a4
+  return 0;
f505a4
+}
f505a4
+_ACEOF
f505a4
+if ac_fn_c_try_link "$LINENO"; then :
f505a4
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
f505a4
+$as_echo "yes" >&6; }
f505a4
+
f505a4
+$as_echo "#define WITH_IDN_OUT_SUPPORT 1" >>confdefs.h
f505a4
+
f505a4
+else
f505a4
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
f505a4
+$as_echo "no" >&6; }
f505a4
+fi
f505a4
+rm -f core conftest.err conftest.$ac_objext \
f505a4
+    conftest$ac_exeext conftest.$ac_ext
f505a4
+
f505a4
+fi
f505a4
+
f505a4
+
f505a4
+
f505a4
+#
f505a4
+# IDN support in general
f505a4
+#
f505a4
+
f505a4
+# check if idnkit and libidn2 are not used at the same time
f505a4
+if test "$use_idnkit" != no && test "$use_libidn2" != no; then
f505a4
+    as_fn_error $? "idnkit and libidn2 cannot be used at the same time." "$LINENO" 5
f505a4
+fi
f505a4
+# the IDN support is on
f505a4
+if test "$use_idnkit" != no || test "$use_libidn2" != no; then
f505a4
+
f505a4
+$as_echo "#define WITH_IDN_SUPPORT 1" >>confdefs.h
f505a4
+
f505a4
+	if test "$use_libidn2" = no || test "$use_libidn2_out" != no; then
f505a4
+
f505a4
+$as_echo "#define WITH_IDN_OUT_SUPPORT 1" >>confdefs.h
f505a4
+
f505a4
+	fi
f505a4
+fi
f505a4
+
f505a4
 #
f505a4
 # Check whether to build Automated Test Framework unit tests
f505a4
 #
f505a4
diff --git a/configure.in b/configure.in
f505a4
index 388356a7c3..63988c97dc 100644
f505a4
--- a/configure.in
f505a4
+++ b/configure.in
f505a4
@@ -4824,24 +4824,24 @@ NOM_PATH_FILE(XSLT_DBLATEX_STYLE, xsl/docbook.xsl, $dblatex_xsl_trees)
f505a4
 NOM_PATH_FILE(XSLT_DBLATEX_FASTBOOK, xsl/latex_book_fast.xsl, $dblatex_xsl_trees)
f505a4
 
f505a4
 #
f505a4
-# IDN support
f505a4
+# IDN support using idnkit
f505a4
 #
f505a4
-AC_ARG_WITH(idn,
f505a4
-	    AS_HELP_STRING([--with-idn[=MPREFIX]],
f505a4
-			   [enable IDN support using idnkit [default PREFIX]]),
f505a4
-	use_idn="$withval", use_idn="no")
f505a4
-case "$use_idn" in
f505a4
+AC_ARG_WITH(idnkit,
f505a4
+	    AS_HELP_STRING([--with-idnkit[=PATH]],
f505a4
+			   [enable IDN support using idnkit [yes|no|path]]),
f505a4
+	use_idnkit="$withval", use_idnkit="no")
f505a4
+case "$use_idnkit" in
f505a4
 yes)
f505a4
 	if test X$prefix = XNONE ; then
f505a4
-		idn_path=/usr/local
f505a4
+		idnkit_path=/usr/local
f505a4
 	else
f505a4
-		idn_path=$prefix
f505a4
+		idnkit_path=$prefix
f505a4
 	fi
f505a4
 	;;
f505a4
 no)
f505a4
 	;;
f505a4
 *)
f505a4
-	idn_path="$use_idn"
f505a4
+	idnkit_path="$use_idnkit"
f505a4
 	;;
f505a4
 esac
f505a4
 
f505a4
@@ -4887,17 +4887,66 @@ if test "yes" = "$idnlib"; then
f505a4
 	AC_MSG_ERROR([You must specify ARG for --with-idnlib.])
f505a4
 fi
f505a4
 
f505a4
-IDNLIBS=
f505a4
-if test "no" != "$use_idn"; then
f505a4
-	AC_DEFINE(WITH_IDN, 1, [define if idnkit support is to be included.])
f505a4
-	STD_CINCLUDES="$STD_CINCLUDES -I$idn_path/include"
f505a4
+IDNKIT_LIBS=
f505a4
+if test "no" != "$use_idnkit"; then
f505a4
+	AC_DEFINE(WITH_IDNKIT, 1, [define if idnkit support is to be included.])
f505a4
+	STD_CINCLUDES="$STD_CINCLUDES -I$idnkit_path/include"
f505a4
 	if test "no" != "$idnlib"; then
f505a4
-		IDNLIBS="$idnlib $iconvlib"
f505a4
+		IDNKIT_LIBS="$idnlib $iconvlib"
f505a4
 	else
f505a4
-		IDNLIBS="-L$idn_path/lib -lidnkit $iconvlib"
f505a4
+		IDNKIT_LIBS="-L$idnkit_path/lib -lidnkit $iconvlib"
f505a4
+	fi
f505a4
+fi
f505a4
+AC_SUBST(IDNKIT_LIBS)
f505a4
+
f505a4
+#
f505a4
+# IDN support using libidn2
f505a4
+#
f505a4
+
f505a4
+LIBIDN2_CFLAGS=
f505a4
+LIBIDN2_LIBS=
f505a4
+AC_ARG_WITH(libidn2,
f505a4
+	AS_HELP_STRING([--with-libidn2[=PATH]], [enable IDN support using GNU libidn2 [yes|no|path]]),
f505a4
+	use_libidn2="$withval", use_libidn2="no")
f505a4
+AS_CASE([$use_libidn2],
f505a4
+	[no],[:],
f505a4
+	[yes],[
f505a4
+	    LIBIDN2_LIBS="-lidn2"
f505a4
+	],
f505a4
+	[*],[
f505a4
+	    LIBIDN2_CFLAGS="-I$use_libidn2/include"
f505a4
+	    LIBIDN2_LIBS="-L$use_libidn2/lib -lidn2"
f505a4
+	])
f505a4
+
f505a4
+AS_IF([test "$use_libidn2" != "no"],
f505a4
+      [AC_SEARCH_LIBS([idn2_to_ascii_8z], [idn2],
f505a4
+		      [AC_DEFINE(WITH_LIBIDN2, 1, [define if libidn2 support is to be included.])],
f505a4
+		      [AC_MSG_ERROR([libidn2 requested, but not found])])
f505a4
+       AC_MSG_CHECKING(whether libidn2 supports idn2_to_unicode_8zlz)
f505a4
+       AC_TRY_LINK([#include <idn2.h>],
f505a4
+		   [idn2_to_unicode_8zlz(".", NULL, IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT);],
f505a4
+		   [AC_MSG_RESULT(yes)
f505a4
+		    AC_DEFINE(WITH_IDN_OUT_SUPPORT, 1, [define if IDN output support is to be included.])],
f505a4
+		   [AC_MSG_RESULT([no])])
f505a4
+      ])
f505a4
+AC_SUBST([LIBIDN2_CFLAGS])
f505a4
+AC_SUBST([LIBIDN2_LIBS])
f505a4
+
f505a4
+#
f505a4
+# IDN support in general
f505a4
+#
f505a4
+
f505a4
+# check if idnkit and libidn2 are not used at the same time
f505a4
+if test "$use_idnkit" != no && test "$use_libidn2" != no; then
f505a4
+    AC_MSG_ERROR([idnkit and libidn2 cannot be used at the same time.])
f505a4
+fi
f505a4
+# the IDN support is on
f505a4
+if test "$use_idnkit" != no || test "$use_libidn2" != no; then
f505a4
+	AC_DEFINE(WITH_IDN_SUPPORT, 1, [define if IDN input support is to be included.])
f505a4
+	if test "$use_libidn2" = no || test "$use_libidn2_out" != no; then
f505a4
+		AC_DEFINE(WITH_IDN_OUT_SUPPORT, 1, [define if IDN output support is to be included.])
f505a4
 	fi
f505a4
 fi
f505a4
-AC_SUBST(IDNLIBS)
f505a4
 
f505a4
 #
f505a4
 # Check whether to build Automated Test Framework unit tests
f505a4
diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml
f505a4
index ec761018c8..ea9b61fd73 100644
f505a4
--- a/doc/arm/notes.xml
f505a4
+++ b/doc/arm/notes.xml
f505a4
@@ -166,6 +166,14 @@
f505a4
 	  [RT #43670]
f505a4
 	</para>
f505a4
       </listitem>
f505a4
+      <listitem>
f505a4
+	<para>
f505a4
+	  <command>named</command> will now log a warning if the old
f505a4
+	  BIND now can be compiled against libidn2 library to add
f505a4
+	  IDNA2008 support.  Previously BIND only supported IDNA2003
f505a4
+	  using (now obsolete) idnkit-1 library.
f505a4
+	</para>
f505a4
+      </listitem>
f505a4
     </itemizedlist>
f505a4
   </section>
f505a4
 
f505a4
@@ -242,6 +250,13 @@
f505a4
 	  Multicast DNS. [RT #44783]
f505a4
 	</para>
f505a4
       </listitem>
f505a4
+      <listitem>
f505a4
+	<para>
f505a4
+	  <command>dig +noidnin</command> can be used to disable IDN
f505a4
+	  processing on the input domain name, when BIND is compiled
f505a4
+	  with IDN support.
f505a4
+	</para>
f505a4
+      </listitem>
f505a4
     </itemizedlist>
f505a4
   </section>
f505a4
 
f505a4
-- 
f505a4
2.14.3
f505a4