#include <idna.h>
#include <stringprep.h>
#endif
+
+#ifdef WITH_LIBIDN2
+#include <idn2.h>
+#endif
#endif /* WITH_IDN_SUPPORT */
#include <dns/byaddr.h>
static isc_result_t libidn_ace_to_locale(const char *from,
char *to,
size_t tolen);
+
+#elif WITH_LIBIDN2
+static isc_result_t libidn2_locale_to_utf8(const char *from,
+ char *to,
+ size_t tolen);
+static isc_result_t libidn2_utf8_to_ace(const char *from,
+ char *to,
+ size_t tolen);
+static isc_result_t libidn2_ace_to_locale(const char *from,
+ char *to,
+ size_t tolen);
#endif
#endif /* WITH_IDN_SUPPORT */
}
result = idn_utf8_to_ace(utf8_textname,
idn_textname, sizeof(idn_textname));
+ if (lookup->origin != NULL && result == ISC_R_NOSPACE) {
+ dns_message_puttempname(lookup->sendmsg,
+ &lookup->name);
+ return ISC_FALSE;
+ }
check_result(result, "convert UTF-8 textname to IDN encoding");
#else /* WITH_IDN_SUPPORT */
static void
idn_initialize(void) {
isc_result_t result;
- char *idn_disable_env = NULL;
#ifdef HAVE_SETLOCALE
/* Set locale */
return (idnkit_locale_to_utf8(from, to, tolen));
#elif WITH_LIBIDN
return (libidn_locale_to_utf8(from, to, tolen));
+#else /* WITH_LIBIDN2 */
+ return (libidn2_locale_to_utf8(from, to, tolen));
#endif
}
return (idnkit_utf8_to_ace(from, to, tolen));
#elif WITH_LIBIDN
return (libidn_utf8_to_ace(from, to, tolen));
+#else /* WITH_LIBIDN2 */
+ return (libidn2_utf8_to_ace(from, to, tolen));
#endif
}
return (idnkit_ace_to_locale(from, to, tolen));
#elif WITH_LIBIDN
return (libidn_ace_to_locale(from, to, tolen));
+#else /* WITH_LIBIDN2 */
+ return (libidn2_ace_to_locale(from, to, tolen));
#endif
}
/* Append dot and origin */
if (namelen + 1 + originlen >= namesize) {
debug("append_textname failure: name + origin is too long");
- return (ISC_R_FAILURE);
+ return (ISC_R_NOSPACE);
}
if (*origin != '.')
} else {
debug("idnkit idn_encodename failed: %s",
idn_result_tostring(result));
- return (ISC_R_FAILURE);
+ if (result == idn_invalid_length)
+ return (ISC_R_NOSPACE);
+ else
+ return (ISC_R_FAILURE);
}
}
static isc_result_t
libidn_utf8_to_ace(const char *from, char *to, size_t tolen) {
int res;
- isc_result_t result;
char *tmp_str = NULL;
res = idna_to_ascii_8z(from, &tmp_str, 0);
/* check the length */
if (strlen(tmp_str) >= tolen) {
debug("encoded ASC string is too long");
- result = ISC_R_FAILURE;
- goto cleanup;
+ return ISC_R_FAILURE;
}
(void) strncpy(to, tmp_str, tolen);
-
- result = ISC_R_SUCCESS;
+ free(tmp_str);
+ return ISC_R_SUCCESS;
} else {
debug("libidn idna_to_ascii_8z failed: %s",
idna_strerror(res));
- result = ISC_R_FAILURE;
}
-cleanup:
- free(tmp_str);
- return (result);
+ return ISC_R_FAILURE;
}
static isc_result_t
return (result);
}
#endif /* WITH_LIBIDN */
+
+#ifdef WITH_LIBIDN2
+/* Converts name from locale directly into ACE format, skip UTF-8 step */
+static isc_result_t
+libidn2_locale_to_utf8(const char *from, char *to, size_t tolen) {
+ int res;
+ char *tmp_str = NULL;
+
+ res = idn2_lookup_ul(from, &tmp_str, IDN2_NONTRANSITIONAL);
+ if (res == IDN2_DISALLOWED)
+ res = idn2_lookup_ul(from, &tmp_str, IDN2_TRANSITIONAL);
+
+ if (res == IDN2_OK) {
+ /* check the length */
+ if (strlen(tmp_str) >= tolen) {
+ debug("ACE string is too long");
+ free(tmp_str);
+ return ISC_R_FAILURE;
+ }
+
+ (void) strncpy(to, tmp_str, tolen);
+ free(tmp_str);
+
+ return ISC_R_SUCCESS;
+ }
+
+ debug("libidn2 idn2_lookup_u8 failed: %s", idn2_strerror(res));
+ return ISC_R_FAILURE;
+}
+
+static isc_result_t
+libidn2_utf8_to_ace(const char *from, char *to, size_t tolen) {
+ int res;
+
+ /* Just check the format again. */
+ res = idn2_to_unicode_8zlz(from, NULL,
+ IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT);
+ if (res == IDN2_OK) {
+ strncpy(to, from, tolen);
+ return ISC_R_SUCCESS;
+ }
+ debug("libidn2 idn2_to_unicode_8zlz failed: %s", idn2_strerror(res));
+ if (res == IDN2_TOO_BIG_DOMAIN)
+ return ISC_R_NOSPACE;
+ else
+ return ISC_R_FAILURE;
+}
+
+static isc_result_t
+libidn2_ace_to_locale(const char *from, char *to, size_t tolen) {
+ int res;
+ char *tmp_str = NULL;
+
+ res = idn2_to_unicode_8zlz(from, &tmp_str,
+ IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT);
+
+ if (res == IDN2_OK) {
+ /* check the length */
+ if (strlen(tmp_str) >= tolen) {
+ debug("encoded ASC string is too long");
+ idn2_free(tmp_str);
+ return ISC_R_FAILURE;
+ }
+
+ (void) strncpy(to, tmp_str, tolen);
+ free(tmp_str);
+ return ISC_R_SUCCESS;
+ } else {
+ debug("libidn idna_to_ascii_8z failed: %s",
+ idn2_strerror(res));
+ }
+
+ return ISC_R_FAILURE;
+}
+#endif /* WITH_LIBIDN2 */
#endif /* WITH_IDN_SUPPORT */
# IDN support using idnkit
#
AC_ARG_WITH(idnkit,
- AS_HELP_STRING([--with-idn[=PREFIX]],
- [enable IDN support using idnkit [default PREFIX]]),
+ AS_HELP_STRING([--with-idn[=PATH]],
+ [enable IDN support using idnkit idnkit yes|no|path]),
use_idnkit="$withval", use_idnkit="no")
case "$use_idnkit" in
yes)
# IDN support using libidn
#
AC_ARG_WITH(libidn,
- [ --with-libidn[=MPREFIX] enable IDN support using GNU libidn [default PREFIX]],
+ [ --with-libidn[=PATH] enable IDN support using GNU libidn yes|no|path],
use_libidn="$withval", use_libidn="no")
case "$use_libidn" in
yes)
fi
AC_SUBST(LIBIDN_LIBS)
+#
+# IDN support using libidn2
+#
+
+AC_ARG_WITH(libidn2,
+ [ --with-libidn2[=PATH] enable IDN support using GNU libidn2 yes|no|path],
+ use_libidn2="$withval", use_libidn2="no")
+case "$use_libidn2" in
+yes)
+ if test X$prefix = XNONE ; then
+ libidn2_path=/usr/local
+ else
+ libidn2_path=$prefix
+ fi
+ ;;
+no)
+ ;;
+*)
+ libidn2_path="$use_libidn2"
+ ;;
+esac
+
+LIBIDN2_LIBS=
+if test "$use_libidn2" != no; then
+ AC_DEFINE(WITH_LIBIDN2, 1, [define if libidn2 support is to be included.])
+ STD_CINCLUDES="$STD_CINCLUDES -I$libidn2_path/include"
+ LIBIDN_LIBS="-lidn2"
+fi
+AC_SUBST(LIBIDN2_LIBS)
+
#
# IDN support in general
#
-# check if idnkit and libidn are not used at the same time
+# check if idnkit, libidn and libidn2 are not used at the same time
if test "$use_idnkit" != no && test "$use_libidn" != no; then
AC_MSG_ERROR([idnkit and libidn cannot be used at the same time.])
fi
+if test "$use_idnkit" != no && test "$use_libidn2" != no; then
+ AC_MSG_ERROR([idnkit and libidn2 cannot be used at the same time.])
+fi
+if test "$use_libidn" != no && test "$use_libidn2" != no; then
+ AC_MSG_ERROR([libidn and libidn2 cannot be used at the same time.])
+fi
# the IDN support is on
-if test "$use_idnkit" != no || test "$use_libidn" != no; then
+if test "$use_idnkit" != no || test "$use_libidn" != no || test "$use_libidn2" != no; then
AC_DEFINE(WITH_IDN_SUPPORT, 1, [define if IDN support is to be included.])
fi