From 2320443f63b14ff926d0b91b479a48e29bc02376 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Wed, 23 Sep 2015 14:37:16 +0200 Subject: [PATCH 1/9] Add support for GNU libidn Added new configure option: --with-libidn - to enable IDN using GNU libidn Renamed configure option: --with-idn to --with-idnkit to make the option usage more clear idnkit and libidn support can not be used at the same time. Signed-off-by: Tomas Hozza --- bin/dig/Makefile.in | 4 +- bin/dig/dighost.c | 347 +++++++++++++++++++++++++++++++++++--------- configure.in | 73 ++++++++-- 3 files changed, 335 insertions(+), 89 deletions(-) diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in index 46a4cf60f7..72e84f21da 100644 --- a/bin/dig/Makefile.in +++ b/bin/dig/Makefile.in @@ -41,10 +41,10 @@ DEPLIBS = ${DNSDEPLIBS} ${IRSDEPLIBS} ${BIND9DEPLIBS} \ ${ISCDEPLIBS} ${ISCCFGDEPLIBS} LIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ - ${ISCLIBS} @IDNLIBS@ @LIBS@ + ${ISCLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBS@ NOSYMLIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ - ${ISCNOSYMLIBS} @IDNLIBS@ @LIBS@ + ${ISCNOSYMLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBS@ SUBDIRS = diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 508c620e67..9510506a84 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -24,18 +24,26 @@ #include #include #include +#include #ifdef HAVE_LOCALE_H #include #endif -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT +#ifdef WITH_IDNKIT #include #include #include #include #endif +#ifdef WITH_LIBIDN +#include +#include +#endif +#endif /* WITH_IDN_SUPPORT */ + #include #include #include @@ -134,18 +142,50 @@ int lookup_counter = 0; static char servercookie[256]; -#ifdef WITH_IDN -static void initialize_idn(void); -static isc_result_t output_filter(isc_buffer_t *buffer, - unsigned int used_org, - isc_boolean_t absolute); -static idn_result_t append_textname(char *name, const char *origin, - size_t namesize); -static void idn_check_result(idn_result_t r, const char *msg); +#ifdef WITH_IDN_SUPPORT +static void idn_initialize(void); +static isc_result_t idn_locale_to_utf8(const char *from, + char *to, + size_t tolen); +static isc_result_t idn_utf8_to_ace(const char *from, + char *to, + size_t tolen); +static isc_result_t idn_ace_to_locale(const char *from, + char *to, + size_t tolen); +static isc_result_t output_filter(isc_buffer_t *buffer, + unsigned int used_org, + isc_boolean_t absolute); +static isc_result_t append_textname(char *name, + const char *origin, + size_t namesize); -#define MAXDLEN 256 -int idnoptions = 0; +#define MAXDLEN 256 + +#ifdef WITH_IDNKIT +static isc_result_t idnkit_initialize(void); +static isc_result_t idnkit_locale_to_utf8(const char *from, + char *to, + size_t tolen); +static isc_result_t idnkit_utf8_to_ace(const char *from, + char *to, + size_t tolen); +static isc_result_t idnkit_ace_to_locale(const char *from, + char *to, + size_t tolen); + +#elif WITH_LIBIDN +static isc_result_t libidn_locale_to_utf8(const char *from, + char *to, + size_t tolen); +static isc_result_t libidn_utf8_to_ace(const char *from, + char *to, + size_t tolen); +static isc_result_t libidn_ace_to_locale(const char *from, + char *to, + size_t tolen); #endif +#endif /* WITH_IDN_SUPPORT */ isc_socket_t *keep = NULL; isc_sockaddr_t keepaddr; @@ -1294,8 +1334,8 @@ setup_system(isc_boolean_t ipv4only, isc_boolean_t ipv6only) { irs_resconf_destroy(&resconf); -#ifdef WITH_IDN - initialize_idn(); +#ifdef WITH_IDN_SUPPORT + idn_initialize(); #endif if (keyfile[0] != 0) @@ -2026,12 +2066,11 @@ setup_lookup(dig_lookup_t *lookup) { char store[MXNAME]; char ecsbuf[20]; char cookiebuf[256]; -#ifdef WITH_IDN - idn_result_t mr; +#ifdef WITH_IDN_SUPPORT char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME]; #endif -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT result = dns_name_settotextfilter(lookup->idnout ? output_filter : NULL); check_result(result, "dns_name_settotextfilter"); @@ -2064,15 +2103,15 @@ setup_lookup(dig_lookup_t *lookup) { isc_buffer_init(&lookup->onamebuf, lookup->oname_space, sizeof(lookup->oname_space)); -#ifdef WITH_IDN /* * We cannot convert `textname' and `origin' separately. * `textname' doesn't contain TLD, but local mapping needs * TLD. */ - mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname, - utf8_textname, sizeof(utf8_textname)); - idn_check_result(mr, "convert textname to UTF-8"); +#ifdef WITH_IDN_SUPPORT + result = idn_locale_to_utf8(lookup->textname, utf8_textname, + sizeof(utf8_textname)); + check_result(result, "convert textname to UTF-8"); #endif /* @@ -2083,17 +2122,12 @@ setup_lookup(dig_lookup_t *lookup) { * is TRUE or we got a domain line in the resolv.conf file. */ if (lookup->new_search) { -#ifdef WITH_IDN - if ((count_dots(utf8_textname) >= ndots) || !usesearch) { - lookup->origin = NULL; /* Force abs lookup */ - lookup->done_as_is = ISC_TRUE; - lookup->need_search = usesearch; - } else if (lookup->origin == NULL && usesearch) { - lookup->origin = ISC_LIST_HEAD(search_list); - lookup->need_search = ISC_FALSE; - } +#ifdef WITH_IDN_SUPPORT + if ((count_dots(utf8_textname) >= ndots) || !usesearch) #else - if ((count_dots(lookup->textname) >= ndots) || !usesearch) { + if ((count_dots(lookup->textname) >= ndots) || !usesearch) +#endif + { lookup->origin = NULL; /* Force abs lookup */ lookup->done_as_is = ISC_TRUE; lookup->need_search = usesearch; @@ -2101,24 +2135,23 @@ setup_lookup(dig_lookup_t *lookup) { lookup->origin = ISC_LIST_HEAD(search_list); lookup->need_search = ISC_FALSE; } -#endif } -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT if (lookup->origin != NULL) { - mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, - lookup->origin->origin, utf8_origin, - sizeof(utf8_origin)); - idn_check_result(mr, "convert origin to UTF-8"); - mr = append_textname(utf8_textname, utf8_origin, - sizeof(utf8_textname)); - idn_check_result(mr, "append origin to textname"); + debug("trying origin %s", lookup->origin->origin); + result = idn_locale_to_utf8(lookup->origin->origin, + utf8_origin, sizeof(utf8_origin)); + check_result(result, "convert origin to UTF-8"); + result = append_textname(utf8_textname, + utf8_origin, sizeof(utf8_textname)); + check_result(result, "append origin to textname"); } - mr = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP | - IDN_IDNCONV | IDN_LENCHECK, utf8_textname, - idn_textname, sizeof(idn_textname)); - idn_check_result(mr, "convert UTF-8 textname to IDN encoding"); -#else + result = idn_utf8_to_ace(utf8_textname, + idn_textname, sizeof(idn_textname)); + check_result(result, "convert UTF-8 textname to IDN encoding"); + +#else /* WITH_IDN_SUPPORT */ if (lookup->origin != NULL) { debug("trying origin %s", lookup->origin->origin); result = dns_message_gettempname(lookup->sendmsg, @@ -2181,21 +2214,17 @@ setup_lookup(dig_lookup_t *lookup) { if (lookup->trace && lookup->trace_root) dns_name_clone(dns_rootname, lookup->name); else { -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT len = (unsigned int) strlen(idn_textname); isc_buffer_init(&b, idn_textname, len); - isc_buffer_add(&b, len); - result = dns_name_fromtext(lookup->name, &b, - dns_rootname, 0, - &lookup->namebuf); #else len = (unsigned int) strlen(lookup->textname); isc_buffer_init(&b, lookup->textname, len); +#endif isc_buffer_add(&b, len); result = dns_name_fromtext(lookup->name, &b, dns_rootname, 0, &lookup->namebuf); -#endif } if (result != ISC_R_SUCCESS) { dns_message_puttempname(lookup->sendmsg, @@ -4153,7 +4182,7 @@ cancel_all(void) { */ void destroy_libs(void) { -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT isc_result_t result; #endif @@ -4187,7 +4216,7 @@ destroy_libs(void) { clear_searchlist(); -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT result = dns_name_settotextfilter(NULL); check_result(result, "dns_name_settotextfilter"); #endif @@ -4234,27 +4263,55 @@ destroy_libs(void) { isc_mem_destroy(&mctx); } -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT static void -initialize_idn(void) { - idn_result_t r; +idn_initialize(void) { isc_result_t result; + char *idn_disable_env = NULL; #ifdef HAVE_SETLOCALE /* Set locale */ (void)setlocale(LC_ALL, ""); #endif + +#ifdef HAVE_IDNKIT /* Create configuration context. */ - r = idn_nameinit(1); - if (r != idn_success) - fatal("idn api initialization failed: %s", - idn_result_tostring(r)); + result = idnkit_initialize(); + check_result(result, "idnkit initializationt"); +#endif /* Set domain name -> text post-conversion filter. */ result = dns_name_settotextfilter(output_filter); check_result(result, "dns_name_settotextfilter"); } +static isc_result_t +idn_locale_to_utf8(const char *from, char *to, size_t tolen) { +#ifdef WITH_IDNKIT + return (idnkit_locale_to_utf8(from, to, tolen)); +#elif WITH_LIBIDN + return (libidn_locale_to_utf8(from, to, tolen)); +#endif +} + +static isc_result_t +idn_utf8_to_ace(const char *from, char *to, size_t tolen) { +#ifdef WITH_IDNKIT + return (idnkit_utf8_to_ace(from, to, tolen)); +#elif WITH_LIBIDN + return (libidn_utf8_to_ace(from, to, tolen)); +#endif +} + +static isc_result_t +idn_ace_to_locale(const char *from, char *to, size_t tolen) { +#ifdef WITH_IDNKIT + return (idnkit_ace_to_locale(from, to, tolen)); +#elif WITH_LIBIDN + return (libidn_ace_to_locale(from, to, tolen)); +#endif +} + static isc_result_t output_filter(isc_buffer_t *buffer, unsigned int used_org, isc_boolean_t absolute) @@ -4262,6 +4319,7 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org, char tmp1[MAXDLEN], tmp2[MAXDLEN]; size_t fromlen, tolen; isc_boolean_t end_with_dot; + isc_result_t result; /* * Copy contents of 'buffer' to 'tmp1', supply trailing dot @@ -4270,6 +4328,7 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org, fromlen = isc_buffer_usedlength(buffer) - used_org; if (fromlen >= MAXDLEN) return (ISC_R_SUCCESS); + memmove(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen); end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE; if (absolute && !end_with_dot) { @@ -4278,12 +4337,14 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org, return (ISC_R_SUCCESS); tmp1[fromlen - 1] = '.'; } + tmp1[fromlen] = '\0'; /* * Convert contents of 'tmp1' to local encoding. */ - if (idn_decodename(IDN_DECODE_APP, tmp1, tmp2, MAXDLEN) != idn_success) + result = idn_ace_to_locale(tmp1, tmp2, sizeof(tmp2)); + if (result != ISC_R_SUCCESS) return (ISC_R_SUCCESS); strlcpy(tmp1, tmp2, MAXDLEN); @@ -4305,31 +4366,173 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org, return (ISC_R_SUCCESS); } -static idn_result_t +static isc_result_t append_textname(char *name, const char *origin, size_t namesize) { size_t namelen = strlen(name); size_t originlen = strlen(origin); /* Already absolute? */ if (namelen > 0 && name[namelen - 1] == '.') - return (idn_success); + return (ISC_R_SUCCESS); /* Append dot and origin */ - - if (namelen + 1 + originlen >= namesize) - return (idn_buffer_overflow); + if (namelen + 1 + originlen >= namesize) { + debug("append_textname failure: name + origin is too long"); + return (ISC_R_FAILURE); + } if (*origin != '.') name[namelen++] = '.'; (void)strlcpy(name + namelen, origin, namesize - namelen); - return (idn_success); + return (ISC_R_SUCCESS); } -static void -idn_check_result(idn_result_t r, const char *msg) { - if (r != idn_success) { - exitcode = 1; - fatal("%s: %s", msg, idn_result_tostring(r)); +#ifdef WITH_IDNKIT +static isc_result_t +idnkit_initialize(void) { + idn_result_t result; + + result = idn_nameinit(1); + + if (result == idn_success) { + return (ISC_R_SUCCESS); + } else { + debug("idnkit api initialization failed: %s", + idn_result_tostring(result)); + return (ISC_R_FAILURE); } } -#endif /* WITH_IDN */ + +static isc_result_t +idnkit_locale_to_utf8(const char *from, char *to, size_t tolen) { + idn_result_t result; + + result = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, from, to, tolen); + + if (result == idn_success) { + return (ISC_R_SUCCESS); + } else { + debug("idnkit idn_encodename failed: %s", + idn_result_tostring(result)); + return (ISC_R_FAILURE); + } +} + +static isc_result_t +idnkit_utf8_to_ace(const char *from, char *to, size_t tolen) { + idn_result_t result; + + result = idn_encodename(IDN_LOCALMAP | IDN_NAMEPREP | + IDN_IDNCONV | IDN_LENCHECK, from, to, tolen); + + if (result == idn_success) { + return (ISC_R_SUCCESS); + } else { + debug("idnkit idn_encodename failed: %s", + idn_result_tostring(result)); + return (ISC_R_FAILURE); + } +} + +static isc_result_t +idnkit_ace_to_locale(const char *from, char *to, size_t tolen) { + idn_result_t result; + + result = idn_decodename(IDN_DECODE_APP, from, to, tolen); + + if (result == idn_success) { + return (ISC_R_SUCCESS); + } else { + debug("idnkit idn_decodename failed: %s", + idn_result_tostring(result) ); + return (ISC_R_FAILURE); + } +} +#endif /* WITH_IDNKIT */ + +#ifdef WITH_LIBIDN +static isc_result_t +libidn_locale_to_utf8(const char *from, char *to, size_t tolen) { + isc_result_t result = ISC_R_FAILURE; + char *tmp_str = NULL; + + tmp_str = stringprep_locale_to_utf8(from); + + if (tmp_str != NULL) { + if (strlen(tmp_str) >= tolen) { + debug("UTF-8 string is too long"); + result = ISC_R_FAILURE; + goto cleanup; + } + + (void) strncpy(to, tmp_str, tolen); + + result = ISC_R_SUCCESS; + } + +cleanup: + free(tmp_str); + return (result); +} + +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); + + if (res == IDNA_SUCCESS) { + /* check the length */ + if (strlen(tmp_str) >= tolen) { + debug("encoded ASC string is too long"); + result = ISC_R_FAILURE; + goto cleanup; + } + + (void) strncpy(to, tmp_str, tolen); + + result = 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); +} + +static isc_result_t +libidn_ace_to_locale(const char *from, char *to, size_t tolen) { + int res; + isc_result_t result; + char *tmp_str = NULL; + + res = idna_to_unicode_8zlz(from, &tmp_str, 0); + + if (res == IDNA_SUCCESS) { + /* check the length */ + if (strlen(tmp_str) >= tolen) { + debug("decoded locale string is too long"); + result = ISC_R_FAILURE; + goto cleanup; + } + + (void) strncpy(to, tmp_str, tolen); + + result = ISC_R_SUCCESS; + } else { + debug("libidn idna_to_unicode_8z8l failed: %s", + idna_strerror(res)); + result = ISC_R_FAILURE; + } + +cleanup: + free(tmp_str); + return (result); +} +#endif /* WITH_LIBIDN */ +#endif /* WITH_IDN_SUPPORT */ diff --git a/configure.in b/configure.in index f2acb659fb..228af0b4bc 100644 --- a/configure.in +++ b/configure.in @@ -4698,24 +4698,24 @@ NOM_PATH_FILE(XSLT_DBLATEX_STYLE, xsl/docbook.xsl, $dblatex_xsl_trees) NOM_PATH_FILE(XSLT_DBLATEX_FASTBOOK, xsl/latex_book_fast.xsl, $dblatex_xsl_trees) # -# IDN support +# IDN support using idnkit # -AC_ARG_WITH(idn, - AS_HELP_STRING([--with-idn[=MPREFIX]], +AC_ARG_WITH(idnkit, + AS_HELP_STRING([--with-idn[=PREFIX]], [enable IDN support using idnkit [default PREFIX]]), - use_idn="$withval", use_idn="no") -case "$use_idn" in + use_idnkit="$withval", use_idnkit="no") +case "$use_idnkit" in yes) if test X$prefix = XNONE ; then - idn_path=/usr/local + idnkit_path=/usr/local else - idn_path=$prefix + idnkit_path=$prefix fi ;; no) ;; *) - idn_path="$use_idn" + idnkit_path="$use_idnkit" ;; esac @@ -4761,17 +4761,60 @@ if test "yes" = "$idnlib"; then AC_MSG_ERROR([You must specify ARG for --with-idnlib.]) fi -IDNLIBS= -if test "no" != "$use_idn"; then - AC_DEFINE(WITH_IDN, 1, [define if idnkit support is to be included.]) - STD_CINCLUDES="$STD_CINCLUDES -I$idn_path/include" +IDNKIT_LIBS= +if test "no" != "$use_idnkit"; then + AC_DEFINE(WITH_IDNKIT, 1, [define if idnkit support is to be included.]) + STD_CINCLUDES="$STD_CINCLUDES -I$idnkit_path/include" if test "no" != "$idnlib"; then - IDNLIBS="$idnlib $iconvlib" + IDNKIT_LIBS="$idnlib $iconvlib" else - IDNLIBS="-L$idn_path/lib -lidnkit $iconvlib" + IDNKIT_LIBS="-L$idnkit_path/lib -lidnkit $iconvlib" fi fi -AC_SUBST(IDNLIBS) +AC_SUBST(IDNKIT_LIBS) + +# +# IDN support using libidn +# +AC_ARG_WITH(libidn, + [ --with-libidn[=MPREFIX] enable IDN support using GNU libidn [default PREFIX]], + use_libidn="$withval", use_libidn="no") +case "$use_libidn" in +yes) + if test X$prefix = XNONE ; then + libidn_path=/usr/local + else + libidn_path=$prefix + fi + ;; +no) + ;; +*) + libidn_path="$use_libidn" + ;; +esac + +LIBIDN_LIBS= +if test "$use_libidn" != no; then + AC_DEFINE(WITH_LIBIDN, 1, [define if libidn support is to be included.]) + STD_CINCLUDES="$STD_CINCLUDES -I$libidn_path/include" + LIBIDN_LIBS="-lidn" +fi +AC_SUBST(LIBIDN_LIBS) + +# +# IDN support in general +# + +# check if idnkit and libidn 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 + +# the IDN support is on +if test "$use_idnkit" != no || test "$use_libidn" != no; then + AC_DEFINE(WITH_IDN_SUPPORT, 1, [define if IDN support is to be included.]) +fi # # Check whether to build Automated Test Framework unit tests From 505f673451d9f94488b99f5af0ea042e3f8e0915 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Wed, 23 Sep 2015 16:47:37 +0200 Subject: [PATCH 2/9] Add support for libidn2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added two new configure options: --with-libidn2 - to enable IDN using GNU libidn2 idnkit, libidn and libidn2 support can not be used at the same time. NOTE: libidn2 does not support punycode back to Unicode characters, so support for this is missing. Signed-off-by: Tomas Hozza Removed iconv, convert directly from locale to ACE Fix libidn2 and idnkit origin appending Make IDN options in help less different Signed-off-by: Petr Menšík --- bin/dig/Makefile.in | 4 +- bin/dig/dig.c | 2 +- bin/dig/dighost.c | 122 +++++++++++++++++++++++++++++++++++++++----- bin/dig/host.c | 8 +-- configure.in | 46 +++++++++++++++-- 5 files changed, 158 insertions(+), 24 deletions(-) diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in index 72e84f21da..0545902ebb 100644 --- a/bin/dig/Makefile.in +++ b/bin/dig/Makefile.in @@ -41,10 +41,10 @@ DEPLIBS = ${DNSDEPLIBS} ${IRSDEPLIBS} ${BIND9DEPLIBS} \ ${ISCDEPLIBS} ${ISCCFGDEPLIBS} LIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ - ${ISCLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBS@ + ${ISCLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBIDN2_LIBS@ @LIBS@ NOSYMLIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ - ${ISCNOSYMLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBS@ + ${ISCNOSYMLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBIDN2_LIBS@ @LIBS@ SUBDIRS = diff --git a/bin/dig/dig.c b/bin/dig/dig.c index cfe05cd7b4..0181db614a 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -1046,7 +1046,7 @@ plus_option(const char *option, isc_boolean_t is_batchfile, break; case 'n': FULLCHECK("idnout"); -#ifndef WITH_IDN +#ifndef WITH_IDN_SUPPORT fprintf(stderr, ";; IDN support not enabled\n"); #else lookup->idnout = state; diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 9510506a84..d752d156a4 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -42,6 +42,10 @@ #include #include #endif + +#ifdef WITH_LIBIDN2 +#include +#endif #endif /* WITH_IDN_SUPPORT */ #include @@ -184,6 +188,17 @@ static isc_result_t libidn_utf8_to_ace(const char *from, 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 */ @@ -2149,6 +2164,11 @@ setup_lookup(dig_lookup_t *lookup) { } 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 */ @@ -4267,7 +4287,6 @@ destroy_libs(void) { static void idn_initialize(void) { isc_result_t result; - char *idn_disable_env = NULL; #ifdef HAVE_SETLOCALE /* Set locale */ @@ -4291,6 +4310,8 @@ idn_locale_to_utf8(const char *from, char *to, size_t tolen) { 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 } @@ -4300,6 +4321,8 @@ idn_utf8_to_ace(const char *from, char *to, size_t tolen) { 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 } @@ -4309,6 +4332,8 @@ idn_ace_to_locale(const char *from, char *to, size_t tolen) { 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 } @@ -4378,7 +4403,7 @@ append_textname(char *name, const char *origin, size_t namesize) { /* 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 != '.') @@ -4414,7 +4439,10 @@ idnkit_locale_to_utf8(const char *from, char *to, size_t tolen) { } 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); } } @@ -4478,7 +4506,6 @@ cleanup: 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); @@ -4487,22 +4514,18 @@ libidn_utf8_to_ace(const char *from, char *to, size_t tolen) { /* 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 @@ -4535,4 +4558,79 @@ cleanup: 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 */ diff --git a/bin/dig/host.c b/bin/dig/host.c index f27b839c7b..5aa242e105 100644 --- a/bin/dig/host.c +++ b/bin/dig/host.c @@ -721,7 +721,7 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { lookup->rdtype != dns_rdatatype_axfr) lookup->rdtype = rdtype; lookup->rdtypeset = ISC_TRUE; -#ifdef WITH_IDN +#ifdef WITH_IDNKIT idnoptions = 0; #endif if (rdtype == dns_rdatatype_axfr) { @@ -736,7 +736,7 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { } else if (rdtype == dns_rdatatype_any) { if (!lookup->tcp_mode_set) lookup->tcp_mode = ISC_TRUE; -#ifdef WITH_IDN +#ifdef WITH_IDNKIT } else if (rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa || rdtype == dns_rdatatype_mx) { @@ -771,7 +771,7 @@ parse_args(isc_boolean_t is_batchfile, int argc, char **argv) { if (!lookup->rdtypeset || lookup->rdtype != dns_rdatatype_axfr) lookup->rdtype = dns_rdatatype_any; -#ifdef WITH_IDN +#ifdef WITH_IDNKIT idnoptions = 0; #endif list_type = dns_rdatatype_any; @@ -885,7 +885,7 @@ main(int argc, char **argv) { ISC_LIST_INIT(search_list); fatalexit = 1; -#ifdef WITH_IDN +#ifdef WITH_IDNKIT idnoptions = IDN_ASCCHECK; #endif diff --git a/configure.in b/configure.in index 228af0b4bc..4c7b06b4b7 100644 --- a/configure.in +++ b/configure.in @@ -4701,8 +4701,8 @@ NOM_PATH_FILE(XSLT_DBLATEX_FASTBOOK, xsl/latex_book_fast.xsl, $dblatex_xsl_trees # 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) @@ -4777,7 +4777,7 @@ AC_SUBST(IDNKIT_LIBS) # 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) @@ -4802,17 +4802,53 @@ if test "$use_libidn" != no; then 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 From 94757c1545259ec3d7d99f3ba7f9baa9ce58e0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Tue, 15 Aug 2017 14:36:59 +0200 Subject: [PATCH 3/9] Remove conversion from locale to utf8 from public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emit fatal failures on locale to ACE encoding Separate idnout support, disable it for libidn2 < 2.0 Add custom path to libidn. Leave default path for multilib support. Allow turning off IDN input processing by dig option Improve documentation, fix support in host Fix configure changes to adjust help text Use strlcpy with size guard Improve IDN variants choosing. Fix idn2 function name. Remove immediate idn_locale_to_ace and idn_ace_to_locale. Signed-off-by: Petr Menšík --- bin/dig/dig.c | 25 ++- bin/dig/dig.docbook | 18 +- bin/dig/dighost.c | 364 ++++++++++++-------------------------- bin/dig/host.c | 2 +- bin/dig/include/dig/dig.h | 3 +- config.h.in | 3 + configure.in | 40 ++++- 7 files changed, 189 insertions(+), 266 deletions(-) diff --git a/bin/dig/dig.c b/bin/dig/dig.c index 0181db614a..482809ccf0 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -190,7 +190,8 @@ help(void) { " +[no]fail (Don't try next server on SERVFAIL)\n" " +[no]header-only (Send query without a question section)\n" " +[no]identify (ID responders in short answers)\n" -" +[no]idnout (convert IDN response)\n" +" +[no]idnin (Parse IDN names)\n" +" +[no]idnout (Convert IDN response)\n" " +[no]ignore (Don't revert to TCP for TC responses.)\n" " +[no]keepalive (Request EDNS TCP keepalive)\n" " +[no]keepopen (Keep the TCP socket open between queries)\n" @@ -1045,13 +1046,29 @@ plus_option(const char *option, isc_boolean_t is_batchfile, lookup->identify = state; break; case 'n': - FULLCHECK("idnout"); + switch (cmd[3]) { + case 'i': + FULLCHECK("idnin"); #ifndef WITH_IDN_SUPPORT - fprintf(stderr, ";; IDN support not enabled\n"); + fprintf(stderr, ";; IDN input support" + " not enabled\n"); #else - lookup->idnout = state; + lookup->idnin = state; #endif break; + case 'o': + FULLCHECK("idnout"); +#ifndef WITH_IDN_OUT_SUPPORT + fprintf(stderr, ";; IDN output support" + " not enabled\n"); +#else + lookup->idnout = state; +#endif + break; + default: + goto invalid_option; + } + break; default: goto invalid_option; } diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook index 219cfd5dee..80318bb32f 100644 --- a/bin/dig/dig.docbook +++ b/bin/dig/dig.docbook @@ -776,6 +776,17 @@ + + + + + Process [do not process] IDN domain names on input. + This requires IDN SUPPORT to have been enabled at + compile time. The default is to process IDN input. + + + + @@ -1288,10 +1299,9 @@ dig +qr www.isc.org any -x 127.0.0.1 isc.org ns +noqr dig appropriately converts character encoding of domain name before sending a request to DNS server or displaying a reply from the server. - If you'd like to turn off the IDN support for some reason, defines - the IDN_DISABLE environment variable. - The IDN support is disabled if the variable is set when - dig runs. + If you'd like to turn off the IDN support for some reason, use + parameters +noidnin and + +noidnout. diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index d752d156a4..efa8b49e36 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -148,59 +148,31 @@ static char servercookie[256]; #ifdef WITH_IDN_SUPPORT static void idn_initialize(void); -static isc_result_t idn_locale_to_utf8(const char *from, - char *to, - size_t tolen); -static isc_result_t idn_utf8_to_ace(const char *from, +static isc_result_t idn_locale_to_ace(const char *from, char *to, size_t tolen); + +#ifdef WITH_IDNKIT +static isc_result_t idnkit_initialize(void); +#endif +#endif /* WITH_IDN_SUPPORT */ + +#ifdef WITH_IDN_OUT_SUPPORT static isc_result_t idn_ace_to_locale(const char *from, char *to, size_t tolen); static isc_result_t output_filter(isc_buffer_t *buffer, unsigned int used_org, isc_boolean_t absolute); -static isc_result_t append_textname(char *name, - const char *origin, - size_t namesize); - #define MAXDLEN 256 #ifdef WITH_IDNKIT -static isc_result_t idnkit_initialize(void); -static isc_result_t idnkit_locale_to_utf8(const char *from, - char *to, - size_t tolen); -static isc_result_t idnkit_utf8_to_ace(const char *from, - char *to, - size_t tolen); -static isc_result_t idnkit_ace_to_locale(const char *from, - char *to, - size_t tolen); - -#elif WITH_LIBIDN -static isc_result_t libidn_locale_to_utf8(const char *from, - char *to, - size_t tolen); -static isc_result_t libidn_utf8_to_ace(const char *from, - char *to, - size_t tolen); -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); +int idnoptions = 0; #endif -#endif /* WITH_IDN_SUPPORT */ +static isc_result_t idn_ace_to_locale(const char *from, + char *to, + size_t tolen); +#endif /* WITH_IDN_OUT_SUPPORT */ isc_socket_t *keep = NULL; isc_sockaddr_t keepaddr; @@ -701,7 +673,12 @@ make_empty_lookup(void) { looknew->ttlunits = ISC_FALSE; looknew->ttlunits = ISC_FALSE; looknew->qr = ISC_FALSE; -#ifdef WITH_IDN +#ifdef WITH_IDN_SUPPORT + looknew->idnin = ISC_TRUE; +#else + looknew->idnin = ISC_FALSE; +#endif +#ifdef WITH_IDN_OUT_SUPPORT looknew->idnout = ISC_TRUE; #else looknew->idnout = ISC_FALSE; @@ -846,6 +823,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { looknew->nocrypto = lookold->nocrypto; looknew->ttlunits = lookold->ttlunits; looknew->qr = lookold->qr; + looknew->idnin = lookold->idnin; looknew->idnout = lookold->idnout; looknew->udpsize = lookold->udpsize; looknew->edns = lookold->edns; @@ -1353,6 +1331,12 @@ setup_system(isc_boolean_t ipv4only, isc_boolean_t ipv6only) { idn_initialize(); #endif +#ifdef WITH_IDN_OUT_SUPPORT + /* Set domain name -> text post-conversion filter. */ + result = dns_name_settotextfilter(output_filter); + check_result(result, "dns_name_settotextfilter"); +#endif + if (keyfile[0] != 0) setup_file_key(); else if (keysecret[0] != 0) @@ -2081,11 +2065,13 @@ setup_lookup(dig_lookup_t *lookup) { char store[MXNAME]; char ecsbuf[20]; char cookiebuf[256]; + char *origin = NULL; + char *textname = NULL; #ifdef WITH_IDN_SUPPORT - char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME]; + char idn_origin[MXNAME], idn_textname[MXNAME]; #endif -#ifdef WITH_IDN_SUPPORT +#ifdef WITH_IDN_OUT_SUPPORT result = dns_name_settotextfilter(lookup->idnout ? output_filter : NULL); check_result(result, "dns_name_settotextfilter"); @@ -2123,10 +2109,15 @@ setup_lookup(dig_lookup_t *lookup) { * `textname' doesn't contain TLD, but local mapping needs * TLD. */ + textname = lookup->textname; #ifdef WITH_IDN_SUPPORT - result = idn_locale_to_utf8(lookup->textname, utf8_textname, - sizeof(utf8_textname)); - check_result(result, "convert textname to UTF-8"); + if (lookup->idnin) { + result = idn_locale_to_ace(lookup->textname, idn_textname, + sizeof(idn_textname)); + check_result(result, "convert textname to IDN encoding"); + debug("idn_textname: %s", idn_textname); + textname = idn_textname; + } #endif /* @@ -2137,11 +2128,7 @@ setup_lookup(dig_lookup_t *lookup) { * is TRUE or we got a domain line in the resolv.conf file. */ if (lookup->new_search) { -#ifdef WITH_IDN_SUPPORT - if ((count_dots(utf8_textname) >= ndots) || !usesearch) -#else - if ((count_dots(lookup->textname) >= ndots) || !usesearch) -#endif + if ((count_dots(textname) >= ndots) || !usesearch) { lookup->origin = NULL; /* Force abs lookup */ lookup->done_as_is = ISC_TRUE; @@ -2152,26 +2139,6 @@ setup_lookup(dig_lookup_t *lookup) { } } -#ifdef WITH_IDN_SUPPORT - if (lookup->origin != NULL) { - debug("trying origin %s", lookup->origin->origin); - result = idn_locale_to_utf8(lookup->origin->origin, - utf8_origin, sizeof(utf8_origin)); - check_result(result, "convert origin to UTF-8"); - result = append_textname(utf8_textname, - utf8_origin, sizeof(utf8_textname)); - check_result(result, "append origin to textname"); - } - 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 */ if (lookup->origin != NULL) { debug("trying origin %s", lookup->origin->origin); result = dns_message_gettempname(lookup->sendmsg, @@ -2179,8 +2146,18 @@ setup_lookup(dig_lookup_t *lookup) { check_result(result, "dns_message_gettempname"); dns_name_init(lookup->oname, NULL); /* XXX Helper funct to conv char* to name? */ - len = (unsigned int) strlen(lookup->origin->origin); - isc_buffer_init(&b, lookup->origin->origin, len); + origin = lookup->origin->origin; +#ifdef WITH_IDN_SUPPORT + if (lookup->idnin) { + result = idn_locale_to_ace(lookup->origin->origin, + idn_origin, sizeof(idn_origin)); + check_result(result, "convert origin to IDN encoding"); + debug("trying idn origin %s", idn_origin); + origin = idn_origin; + } +#endif + len = (unsigned int) strlen(origin); + isc_buffer_init(&b, origin, len); isc_buffer_add(&b, len); result = dns_name_fromtext(lookup->oname, &b, dns_rootname, 0, &lookup->onamebuf); @@ -2190,7 +2167,7 @@ setup_lookup(dig_lookup_t *lookup) { dns_message_puttempname(lookup->sendmsg, &lookup->oname); fatal("'%s' is not in legal name syntax (%s)", - lookup->origin->origin, + origin, isc_result_totext(result)); } if (lookup->trace && lookup->trace_root) { @@ -2201,8 +2178,8 @@ setup_lookup(dig_lookup_t *lookup) { dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); - len = (unsigned int) strlen(lookup->textname); - isc_buffer_init(&b, lookup->textname, len); + len = (unsigned int) strlen(textname); + isc_buffer_init(&b, textname, len); isc_buffer_add(&b, len); result = dns_name_fromtext(name, &b, NULL, 0, NULL); if (result == ISC_R_SUCCESS && @@ -2227,20 +2204,13 @@ setup_lookup(dig_lookup_t *lookup) { } } dns_message_puttempname(lookup->sendmsg, &lookup->oname); - } else -#endif - { + } else { debug("using root origin"); if (lookup->trace && lookup->trace_root) dns_name_clone(dns_rootname, lookup->name); else { -#ifdef WITH_IDN_SUPPORT - len = (unsigned int) strlen(idn_textname); - isc_buffer_init(&b, idn_textname, len); -#else - len = (unsigned int) strlen(lookup->textname); - isc_buffer_init(&b, lookup->textname, len); -#endif + len = (unsigned int) strlen(textname); + isc_buffer_init(&b, textname, len); isc_buffer_add(&b, len); result = dns_name_fromtext(lookup->name, &b, dns_rootname, 0, @@ -4286,57 +4256,23 @@ destroy_libs(void) { #ifdef WITH_IDN_SUPPORT static void idn_initialize(void) { +#ifdef WITH_IDNKIT isc_result_t result; +#endif #ifdef HAVE_SETLOCALE /* Set locale */ (void)setlocale(LC_ALL, ""); #endif -#ifdef HAVE_IDNKIT +#ifdef WITH_IDNKIT /* Create configuration context. */ result = idnkit_initialize(); check_result(result, "idnkit initializationt"); #endif - - /* Set domain name -> text post-conversion filter. */ - result = dns_name_settotextfilter(output_filter); - check_result(result, "dns_name_settotextfilter"); -} - -static isc_result_t -idn_locale_to_utf8(const char *from, char *to, size_t tolen) { -#ifdef WITH_IDNKIT - 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 -} - -static isc_result_t -idn_utf8_to_ace(const char *from, char *to, size_t tolen) { -#ifdef WITH_IDNKIT - 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 -} - -static isc_result_t -idn_ace_to_locale(const char *from, char *to, size_t tolen) { -#ifdef WITH_IDNKIT - 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 } +#ifdef WITH_IDN_OUT_SUPPORT static isc_result_t output_filter(isc_buffer_t *buffer, unsigned int used_org, isc_boolean_t absolute) @@ -4369,8 +4305,9 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org, * Convert contents of 'tmp1' to local encoding. */ result = idn_ace_to_locale(tmp1, tmp2, sizeof(tmp2)); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { return (ISC_R_SUCCESS); + } strlcpy(tmp1, tmp2, MAXDLEN); /* @@ -4390,146 +4327,97 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org, return (ISC_R_SUCCESS); } - -static isc_result_t -append_textname(char *name, const char *origin, size_t namesize) { - size_t namelen = strlen(name); - size_t originlen = strlen(origin); - - /* Already absolute? */ - if (namelen > 0 && name[namelen - 1] == '.') - return (ISC_R_SUCCESS); - - /* Append dot and origin */ - if (namelen + 1 + originlen >= namesize) { - debug("append_textname failure: name + origin is too long"); - return (ISC_R_NOSPACE); - } - - if (*origin != '.') - name[namelen++] = '.'; - (void)strlcpy(name + namelen, origin, namesize - namelen); - return (ISC_R_SUCCESS); -} +#endif #ifdef WITH_IDNKIT +static void +idnkit_check_result(idn_result_t result, const char *msg) { + if (result != idn_success) { + fatal("%s: %s", msg, idn_result_tostring(result)); + } +} + static isc_result_t idnkit_initialize(void) { idn_result_t result; result = idn_nameinit(1); - - if (result == idn_success) { - return (ISC_R_SUCCESS); - } else { - debug("idnkit api initialization failed: %s", - idn_result_tostring(result)); - return (ISC_R_FAILURE); - } + idnkit_check_result(result, "idnkit api initialization failed"); + return (ISC_R_SUCCESS); } static isc_result_t -idnkit_locale_to_utf8(const char *from, char *to, size_t tolen) { +idn_locale_to_ace(const char *from, char *to, size_t tolen) { + char utf8_textname[MXNAME]; idn_result_t result; - result = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, from, to, tolen); + result = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, from, + utf8_textname, sizeof(utf8_textname)); + idnkit_check_result(result, "idnkit idn_encodename to utf8 failed"); - if (result == idn_success) { - return (ISC_R_SUCCESS); - } else { - debug("idnkit idn_encodename failed: %s", - idn_result_tostring(result)); - if (result == idn_invalid_length) - return (ISC_R_NOSPACE); - else - return (ISC_R_FAILURE); - } + result = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP | + IDN_IDNCONV | IDN_LENCHECK, + utf8_textname, to, tolen); + idnkit_check_result(result, "idnkit idn_encodename to idn failed"); + return (ISC_R_SUCCESS); } static isc_result_t -idnkit_utf8_to_ace(const char *from, char *to, size_t tolen) { - idn_result_t result; - - result = idn_encodename(IDN_LOCALMAP | IDN_NAMEPREP | - IDN_IDNCONV | IDN_LENCHECK, from, to, tolen); - - if (result == idn_success) { - return (ISC_R_SUCCESS); - } else { - debug("idnkit idn_encodename failed: %s", - idn_result_tostring(result)); - return (ISC_R_FAILURE); - } -} - -static isc_result_t -idnkit_ace_to_locale(const char *from, char *to, size_t tolen) { +idn_ace_to_locale(const char *from, char *to, size_t tolen) { idn_result_t result; result = idn_decodename(IDN_DECODE_APP, from, to, tolen); - - if (result == idn_success) { - return (ISC_R_SUCCESS); - } else { + if (result != idn_success) { debug("idnkit idn_decodename failed: %s", - idn_result_tostring(result) ); + idn_result_tostring(result)); return (ISC_R_FAILURE); } + return (ISC_R_SUCCESS); } #endif /* WITH_IDNKIT */ #ifdef WITH_LIBIDN static isc_result_t -libidn_locale_to_utf8(const char *from, char *to, size_t tolen) { +idn_locale_to_ace(const char *from, char *to, size_t tolen) { isc_result_t result = ISC_R_FAILURE; + int res; char *tmp_str = NULL; + char *ace_str = NULL; tmp_str = stringprep_locale_to_utf8(from); if (tmp_str != NULL) { if (strlen(tmp_str) >= tolen) { debug("UTF-8 string is too long"); - result = ISC_R_FAILURE; - goto cleanup; + free(tmp_str); + return ISC_R_NOSPACE; } - - (void) strncpy(to, tmp_str, tolen); - - result = ISC_R_SUCCESS; } + else + return ISC_R_FAILURE; -cleanup: - free(tmp_str); - return (result); -} - -static isc_result_t -libidn_utf8_to_ace(const char *from, char *to, size_t tolen) { - int res; - char *tmp_str = NULL; - - res = idna_to_ascii_8z(from, &tmp_str, 0); - + res = idna_to_ascii_8z(tmp_str, &ace_str, 0); if (res == IDNA_SUCCESS) { /* check the length */ if (strlen(tmp_str) >= tolen) { debug("encoded ASC string is too long"); - return ISC_R_FAILURE; + result = ISC_R_NOSPACE; + } else { + (void) strncpy(to, ace_str, tolen); + result = ISC_R_SUCCESS; } - - (void) strncpy(to, tmp_str, tolen); - free(tmp_str); - return ISC_R_SUCCESS; - } else { - debug("libidn idna_to_ascii_8z failed: %s", - idna_strerror(res)); } - return ISC_R_FAILURE; + free(tmp_str); + free(ace_str); + if (res != IDNA_SUCCESS) { + fatal("idna_to_ascii_8z failed: %s", idna_strerror(res)); + } + return (result); } static isc_result_t -libidn_ace_to_locale(const char *from, char *to, size_t tolen) { +idn_ace_to_locale(const char *from, char *to, size_t tolen) { int res; isc_result_t result; char *tmp_str = NULL; @@ -4548,7 +4436,7 @@ libidn_ace_to_locale(const char *from, char *to, size_t tolen) { result = ISC_R_SUCCESS; } else { - debug("libidn idna_to_unicode_8z8l failed: %s", + debug("idna_to_unicode_8z8l failed: %s", idna_strerror(res)); result = ISC_R_FAILURE; } @@ -4560,9 +4448,8 @@ cleanup: #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) { +idn_locale_to_ace(const char *from, char *to, size_t tolen) { int res; char *tmp_str = NULL; @@ -4574,40 +4461,22 @@ libidn2_locale_to_utf8(const char *from, char *to, size_t tolen) { /* check the length */ if (strlen(tmp_str) >= tolen) { debug("ACE string is too long"); - free(tmp_str); - return ISC_R_FAILURE; + idn2_free(tmp_str); + return ISC_R_NOSPACE; } - (void) strncpy(to, tmp_str, tolen); - free(tmp_str); - + (void) strlcpy(to, tmp_str, tolen); + idn2_free(tmp_str); return ISC_R_SUCCESS; } - debug("libidn2 idn2_lookup_u8 failed: %s", idn2_strerror(res)); + fatal("idn2_lookup_ul failed: %s", idn2_strerror(res)); return ISC_R_FAILURE; } +#ifdef WITH_IDN_OUT_SUPPORT 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) { +idn_ace_to_locale(const char *from, char *to, size_t tolen) { int res; char *tmp_str = NULL; @@ -4626,11 +4495,12 @@ libidn2_ace_to_locale(const char *from, char *to, size_t tolen) { free(tmp_str); return ISC_R_SUCCESS; } else { - debug("libidn idna_to_ascii_8z failed: %s", + debug("idn2_to_unicode_8zlz failed: %s", idn2_strerror(res)); } return ISC_R_FAILURE; } +#endif /* WITH_IDN_OUT_SUPPORT */ #endif /* WITH_LIBIDN2 */ #endif /* WITH_IDN_SUPPORT */ diff --git a/bin/dig/host.c b/bin/dig/host.c index 5aa242e105..cbb548d2fc 100644 --- a/bin/dig/host.c +++ b/bin/dig/host.c @@ -19,7 +19,7 @@ #include #endif -#ifdef WITH_IDN +#ifdef WITH_IDNKIT #include #include #include diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index 48fc8f14b5..b08e99f94b 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -129,6 +129,7 @@ struct dig_lookup { use_usec, nocrypto, ttlunits, + idnin, idnout, qr; char textname[MXNAME]; /*% Name we're going to be looking up */ @@ -268,7 +269,7 @@ extern char *progname; extern int tries; extern int fatalexit; extern isc_boolean_t verbose; -#ifdef WITH_IDN +#ifdef WITH_IDNKIT extern int idnoptions; #endif diff --git a/config.h.in b/config.h.in index 79eba6384e..757a1730db 100644 --- a/config.h.in +++ b/config.h.in @@ -599,6 +599,9 @@ int sigwait(const unsigned int *set, int *sig); /* define if idnkit support is to be included. */ #undef WITH_IDN +#undef WITH_IDN_OUT_SUPPORT + +/* define if IDN input support is to be included. */ /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD diff --git a/configure.in b/configure.in index 4c7b06b4b7..7962465151 100644 --- a/configure.in +++ b/configure.in @@ -4701,8 +4701,8 @@ NOM_PATH_FILE(XSLT_DBLATEX_FASTBOOK, xsl/latex_book_fast.xsl, $dblatex_xsl_trees # IDN support using idnkit # AC_ARG_WITH(idnkit, - AS_HELP_STRING([--with-idn[=PATH]], - [enable IDN support using idnkit idnkit yes|no|path]), + AS_HELP_STRING([--with-idnkit[=PATH]], + [enable IDN support using idnkit [yes|no|path]]), use_idnkit="$withval", use_idnkit="no") case "$use_idnkit" in yes) @@ -4776,8 +4776,9 @@ AC_SUBST(IDNKIT_LIBS) # # IDN support using libidn # +LIBIDN_LIBS= AC_ARG_WITH(libidn, - [ --with-libidn[=PATH] enable IDN support using GNU libidn yes|no|path], + AS_HELP_STRING([--with-libidn[=PATH]], [enable IDN support using GNU libidn [yes|no|path]]), use_libidn="$withval", use_libidn="no") case "$use_libidn" in yes) @@ -4786,19 +4787,19 @@ yes) else libidn_path=$prefix fi + LIBIDN_LIBS="-lidn" ;; no) ;; *) + LIBIDN_LIBS="-L$use_libidn/lib -lidn" libidn_path="$use_libidn" ;; esac -LIBIDN_LIBS= if test "$use_libidn" != no; then AC_DEFINE(WITH_LIBIDN, 1, [define if libidn support is to be included.]) STD_CINCLUDES="$STD_CINCLUDES -I$libidn_path/include" - LIBIDN_LIBS="-lidn" fi AC_SUBST(LIBIDN_LIBS) @@ -4806,8 +4807,9 @@ AC_SUBST(LIBIDN_LIBS) # IDN support using libidn2 # +LIBIDN2_LIBS= AC_ARG_WITH(libidn2, - [ --with-libidn2[=PATH] enable IDN support using GNU libidn2 yes|no|path], + AS_HELP_STRING([--with-libidn2[=PATH]], [enable IDN support using GNU libidn2 [yes|no|path]]), use_libidn2="$withval", use_libidn2="no") case "$use_libidn2" in yes) @@ -4816,19 +4818,36 @@ yes) else libidn2_path=$prefix fi + LIBIDN2_LIBS="-lidn2" ;; no) ;; *) libidn2_path="$use_libidn2" + LIBIDN2_LIBS="-L$libidn2_path/lib -lidn2" ;; esac -LIBIDN2_LIBS= if test "$use_libidn2" != no; then AC_DEFINE(WITH_LIBIDN2, 1, [define if libidn2 support is to be included.]) + saved_cflags="$CFLAGS" + saved_libs="$LIBS" + LIBS="$LIBIDN2_LIBS" + CFLAGS="-I$libidn2_path/include" + + AC_MSG_NOTICE(checking for idn2_to_unicode_8zlz) +AC_TRY_LINK([ +#include +],[ idn2_to_unicode_8zlz(".", NULL, IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT); ], + [AC_MSG_RESULT(yes) + use_libidn2_out=yes], + [AC_MSG_RESULT(no) + use_libidn2_out=no] +) + STD_CINCLUDES="$STD_CINCLUDES -I$libidn2_path/include" - LIBIDN_LIBS="-lidn2" + LIBS="$saved_libs" + CFLAGS="$saved_cflags" fi AC_SUBST(LIBIDN2_LIBS) @@ -4849,7 +4868,10 @@ fi # the IDN support is on 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.]) + AC_DEFINE(WITH_IDN_SUPPORT, 1, [define if IDN input support is to be included.]) + if test "$use_libidn2" = no || test "$use_libidn2_out" != no; then + AC_DEFINE(WITH_IDN_OUT_SUPPORT, 1, [define if IDN output support is to be included.]) + fi fi # From 8254cf69d34947713c99839dd5139f326d8e5d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Wed, 6 Dec 2017 17:12:44 +0100 Subject: [PATCH 4/9] Remove support for libidn (IDN 2003) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Petr Menšík --- bin/dig/Makefile.in | 4 +-- bin/dig/dighost.c | 76 --------------------------------------------- configure.in | 41 ++---------------------- 3 files changed, 4 insertions(+), 117 deletions(-) diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in index 0545902ebb..3531c9b6c2 100644 --- a/bin/dig/Makefile.in +++ b/bin/dig/Makefile.in @@ -41,10 +41,10 @@ DEPLIBS = ${DNSDEPLIBS} ${IRSDEPLIBS} ${BIND9DEPLIBS} \ ${ISCDEPLIBS} ${ISCCFGDEPLIBS} LIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ - ${ISCLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBIDN2_LIBS@ @LIBS@ + ${ISCLIBS} @IDNKIT_LIBS@ @LIBIDN2_LIBS@ @LIBS@ NOSYMLIBS = ${DNSLIBS} ${IRSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ - ${ISCNOSYMLIBS} @IDNKIT_LIBS@ @LIBIDN_LIBS@ @LIBIDN2_LIBS@ @LIBS@ + ${ISCNOSYMLIBS} @IDNKIT_LIBS@ @LIBIDN2_LIBS@ @LIBS@ SUBDIRS = diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index efa8b49e36..b122a37f37 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -38,11 +38,6 @@ #include #endif -#ifdef WITH_LIBIDN -#include -#include -#endif - #ifdef WITH_LIBIDN2 #include #endif @@ -4376,77 +4371,6 @@ idn_ace_to_locale(const char *from, char *to, size_t tolen) { } #endif /* WITH_IDNKIT */ -#ifdef WITH_LIBIDN -static isc_result_t -idn_locale_to_ace(const char *from, char *to, size_t tolen) { - isc_result_t result = ISC_R_FAILURE; - int res; - char *tmp_str = NULL; - char *ace_str = NULL; - - tmp_str = stringprep_locale_to_utf8(from); - - if (tmp_str != NULL) { - if (strlen(tmp_str) >= tolen) { - debug("UTF-8 string is too long"); - free(tmp_str); - return ISC_R_NOSPACE; - } - } - else - return ISC_R_FAILURE; - - res = idna_to_ascii_8z(tmp_str, &ace_str, 0); - if (res == IDNA_SUCCESS) { - /* check the length */ - if (strlen(tmp_str) >= tolen) { - debug("encoded ASC string is too long"); - result = ISC_R_NOSPACE; - } else { - (void) strncpy(to, ace_str, tolen); - result = ISC_R_SUCCESS; - } - } - - free(tmp_str); - free(ace_str); - if (res != IDNA_SUCCESS) { - fatal("idna_to_ascii_8z failed: %s", idna_strerror(res)); - } - return (result); -} - -static isc_result_t -idn_ace_to_locale(const char *from, char *to, size_t tolen) { - int res; - isc_result_t result; - char *tmp_str = NULL; - - res = idna_to_unicode_8zlz(from, &tmp_str, 0); - - if (res == IDNA_SUCCESS) { - /* check the length */ - if (strlen(tmp_str) >= tolen) { - debug("decoded locale string is too long"); - result = ISC_R_FAILURE; - goto cleanup; - } - - (void) strncpy(to, tmp_str, tolen); - - result = ISC_R_SUCCESS; - } else { - debug("idna_to_unicode_8z8l failed: %s", - idna_strerror(res)); - result = ISC_R_FAILURE; - } - -cleanup: - free(tmp_str); - return (result); -} -#endif /* WITH_LIBIDN */ - #ifdef WITH_LIBIDN2 static isc_result_t idn_locale_to_ace(const char *from, char *to, size_t tolen) { diff --git a/configure.in b/configure.in index 7962465151..dacc693b17 100644 --- a/configure.in +++ b/configure.in @@ -4773,36 +4773,6 @@ if test "no" != "$use_idnkit"; then fi AC_SUBST(IDNKIT_LIBS) -# -# IDN support using libidn -# -LIBIDN_LIBS= -AC_ARG_WITH(libidn, - AS_HELP_STRING([--with-libidn[=PATH]], [enable IDN support using GNU libidn [yes|no|path]]), - use_libidn="$withval", use_libidn="no") -case "$use_libidn" in -yes) - if test X$prefix = XNONE ; then - libidn_path=/usr/local - else - libidn_path=$prefix - fi - LIBIDN_LIBS="-lidn" - ;; -no) - ;; -*) - LIBIDN_LIBS="-L$use_libidn/lib -lidn" - libidn_path="$use_libidn" - ;; -esac - -if test "$use_libidn" != no; then - AC_DEFINE(WITH_LIBIDN, 1, [define if libidn support is to be included.]) - STD_CINCLUDES="$STD_CINCLUDES -I$libidn_path/include" -fi -AC_SUBST(LIBIDN_LIBS) - # # IDN support using libidn2 # @@ -4855,19 +4825,12 @@ AC_SUBST(LIBIDN2_LIBS) # IDN support in general # -# 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 +# check if idnkit and libidn2 are not used at the same time 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 || test "$use_libidn2" != no; then +if test "$use_idnkit" != no || test "$use_libidn2" != no; then AC_DEFINE(WITH_IDN_SUPPORT, 1, [define if IDN input support is to be included.]) if test "$use_libidn2" = no || test "$use_libidn2_out" != no; then AC_DEFINE(WITH_IDN_OUT_SUPPORT, 1, [define if IDN output support is to be included.]) From 29b94bbb04014681afe61c1594b99f6ec30f6b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Thu, 22 Feb 2018 17:11:18 +0100 Subject: [PATCH 5/9] Sanitize IDN initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Petr Menšík --- bin/dig/dighost.c | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index b122a37f37..c5d027bd4f 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -146,10 +146,6 @@ static void idn_initialize(void); static isc_result_t idn_locale_to_ace(const char *from, char *to, size_t tolen); - -#ifdef WITH_IDNKIT -static isc_result_t idnkit_initialize(void); -#endif #endif /* WITH_IDN_SUPPORT */ #ifdef WITH_IDN_OUT_SUPPORT @@ -164,9 +160,6 @@ static isc_result_t output_filter(isc_buffer_t *buffer, #ifdef WITH_IDNKIT int idnoptions = 0; #endif -static isc_result_t idn_ace_to_locale(const char *from, - char *to, - size_t tolen); #endif /* WITH_IDN_OUT_SUPPORT */ isc_socket_t *keep = NULL; @@ -1322,6 +1315,11 @@ setup_system(isc_boolean_t ipv4only, isc_boolean_t ipv6only) { irs_resconf_destroy(&resconf); +#ifdef HAVE_SETLOCALE + /* Set locale */ + (void)setlocale(LC_ALL, ""); +#endif + #ifdef WITH_IDN_SUPPORT idn_initialize(); #endif @@ -4248,25 +4246,6 @@ destroy_libs(void) { isc_mem_destroy(&mctx); } -#ifdef WITH_IDN_SUPPORT -static void -idn_initialize(void) { -#ifdef WITH_IDNKIT - isc_result_t result; -#endif - -#ifdef HAVE_SETLOCALE - /* Set locale */ - (void)setlocale(LC_ALL, ""); -#endif - -#ifdef WITH_IDNKIT - /* Create configuration context. */ - result = idnkit_initialize(); - check_result(result, "idnkit initializationt"); -#endif -} - #ifdef WITH_IDN_OUT_SUPPORT static isc_result_t output_filter(isc_buffer_t *buffer, unsigned int used_org, @@ -4324,6 +4303,7 @@ output_filter(isc_buffer_t *buffer, unsigned int used_org, } #endif +#ifdef WITH_IDN_SUPPORT #ifdef WITH_IDNKIT static void idnkit_check_result(idn_result_t result, const char *msg) { @@ -4332,10 +4312,11 @@ idnkit_check_result(idn_result_t result, const char *msg) { } } -static isc_result_t -idnkit_initialize(void) { +static void +idn_initialize(void) { idn_result_t result; + /* Create configuration context. */ result = idn_nameinit(1); idnkit_check_result(result, "idnkit api initialization failed"); return (ISC_R_SUCCESS); @@ -4372,6 +4353,10 @@ idn_ace_to_locale(const char *from, char *to, size_t tolen) { #endif /* WITH_IDNKIT */ #ifdef WITH_LIBIDN2 +static void +idn_initialize(void) { +} + static isc_result_t idn_locale_to_ace(const char *from, char *to, size_t tolen) { int res; From 76c05a71fcf464d6a638b2d8fab589100850e3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 14 Mar 2018 11:30:47 +0100 Subject: [PATCH 6/9] Simplify the libidn2 configure checks --- bin/dig/Makefile.in | 2 +- config.h.in | 8 +- configure | 195 +++++++++++++++++++++++++++++++++++++------- configure.in | 61 ++++++-------- 4 files changed, 195 insertions(+), 71 deletions(-) diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in index 3531c9b6c2..ceb272d0a2 100644 --- a/bin/dig/Makefile.in +++ b/bin/dig/Makefile.in @@ -19,7 +19,7 @@ READLINE_LIB = @READLINE_LIB@ CINCLUDES = -I${srcdir}/include ${DNS_INCLUDES} \ ${BIND9_INCLUDES} ${ISC_INCLUDES} \ - ${IRS_INCLUDES} ${ISCCFG_INCLUDES} @DST_OPENSSL_INC@ + ${IRS_INCLUDES} ${ISCCFG_INCLUDES} @LIBIDN2_CFLAGS@ @DST_OPENSSL_INC@ CDEFINES = -DVERSION=\"${VERSION}\" @CRYPTO@ CWARNINGS = diff --git a/config.h.in b/config.h.in index 757a1730db..52277996f9 100644 --- a/config.h.in +++ b/config.h.in @@ -597,11 +597,17 @@ int sigwait(const unsigned int *set, int *sig); #undef WANT_QUERYTRACE /* define if idnkit support is to be included. */ -#undef WITH_IDN +#undef WITH_IDNKIT +/* define if IDN output support is to be included. */ #undef WITH_IDN_OUT_SUPPORT /* define if IDN input support is to be included. */ +#undef WITH_IDN_SUPPORT + +/* define if libidn2 support is to be included. */ +#undef WITH_LIBIDN2 + /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD diff --git a/configure b/configure index 4073acba3b..5a64ba72bf 100755 --- a/configure +++ b/configure @@ -681,7 +681,9 @@ UNITTESTS ATFLIBS ATFBIN ATFBUILD -IDNLIBS +LIBIDN2_LIBS +LIBIDN2_CFLAGS +IDNKIT_LIBS XSLT_DBLATEX_FASTBOOK XSLT_DBLATEX_STYLE XSLT_DOCBOOK_MAKETOC_XHTML @@ -942,7 +944,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1041,10 +1042,11 @@ enable_dnstap with_protobuf_c with_libfstrm with_docbook_xsl -with_idn +with_idnkit with_libiconv with_iconv with_idnlib +with_libidn2 with_atf with_tuning enable_querytrace @@ -1107,7 +1109,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1360,15 +1361,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1506,7 +1498,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1659,7 +1651,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1786,10 +1777,11 @@ Optional Packages: --with-protobuf-c=path Path where protobuf-c is installed, for dnstap --with-libfstrm=path Path where libfstrm is installed, for dnstap --with-docbook-xsl=PATH specify path for Docbook-XSL stylesheets - --with-idn=MPREFIX enable IDN support using idnkit [default PREFIX] + --with-idnkit=PATH enable IDN support using idnkit [yes|no|path] --with-libiconv=IPREFIX GNU libiconv are in IPREFIX [default PREFIX] --with-iconv=LIBSPEC specify iconv library [default -liconv] --with-idnlib=ARG specify libidnkit + --with-libidn2=PATH enable IDN support using GNU libidn2 [yes|no|path] --with-atf support Automated Test Framework --with-tuning=ARG Specify server tuning (large or default) --with-dlopen=ARG support dynamically loadable DLZ drivers @@ -22552,28 +22544,28 @@ fi # -# IDN support +# IDN support using idnkit # -# Check whether --with-idn was given. -if test "${with_idn+set}" = set; then : - withval=$with_idn; use_idn="$withval" +# Check whether --with-idnkit was given. +if test "${with_idnkit+set}" = set; then : + withval=$with_idnkit; use_idnkit="$withval" else - use_idn="no" + use_idnkit="no" fi -case "$use_idn" in +case "$use_idnkit" in yes) if test X$prefix = XNONE ; then - idn_path=/usr/local + idnkit_path=/usr/local else - idn_path=$prefix + idnkit_path=$prefix fi ;; no) ;; *) - idn_path="$use_idn" + idnkit_path="$use_idnkit" ;; esac @@ -22630,20 +22622,161 @@ if test "yes" = "$idnlib"; then as_fn_error $? "You must specify ARG for --with-idnlib." "$LINENO" 5 fi -IDNLIBS= -if test "no" != "$use_idn"; then +IDNKIT_LIBS= +if test "no" != "$use_idnkit"; then -$as_echo "#define WITH_IDN 1" >>confdefs.h +$as_echo "#define WITH_IDNKIT 1" >>confdefs.h - STD_CINCLUDES="$STD_CINCLUDES -I$idn_path/include" + STD_CINCLUDES="$STD_CINCLUDES -I$idnkit_path/include" if test "no" != "$idnlib"; then - IDNLIBS="$idnlib $iconvlib" + IDNKIT_LIBS="$idnlib $iconvlib" else - IDNLIBS="-L$idn_path/lib -lidnkit $iconvlib" + IDNKIT_LIBS="-L$idnkit_path/lib -lidnkit $iconvlib" fi fi +# +# IDN support using libidn2 +# + +LIBIDN2_CFLAGS= +LIBIDN2_LIBS= + +# Check whether --with-libidn2 was given. +if test "${with_libidn2+set}" = set; then : + withval=$with_libidn2; use_libidn2="$withval" +else + use_libidn2="no" +fi + +case $use_libidn2 in #( + no) : + : ;; #( + yes) : + + LIBIDN2_LIBS="-lidn2" + ;; #( + *) : + + LIBIDN2_CFLAGS="-I$use_libidn2/include" + LIBIDN2_LIBS="-L$use_libidn2/lib -lidn2" + ;; #( + *) : + ;; +esac + +if test "$use_libidn2" != "no"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing idn2_to_ascii_8z" >&5 +$as_echo_n "checking for library containing idn2_to_ascii_8z... " >&6; } +if ${ac_cv_search_idn2_to_ascii_8z+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char idn2_to_ascii_8z (); +int +main () +{ +return idn2_to_ascii_8z (); + ; + return 0; +} +_ACEOF +for ac_lib in '' idn2; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_idn2_to_ascii_8z=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_idn2_to_ascii_8z+:} false; then : + break +fi +done +if ${ac_cv_search_idn2_to_ascii_8z+:} false; then : + +else + ac_cv_search_idn2_to_ascii_8z=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_idn2_to_ascii_8z" >&5 +$as_echo "$ac_cv_search_idn2_to_ascii_8z" >&6; } +ac_res=$ac_cv_search_idn2_to_ascii_8z +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define WITH_LIBIDN2 1" >>confdefs.h + +else + as_fn_error $? "libidn2 requested, but not found" "$LINENO" 5 +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libidn2 supports idn2_to_unicode_8zlz" >&5 +$as_echo_n "checking whether libidn2 supports idn2_to_unicode_8zlz... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +idn2_to_unicode_8zlz(".", NULL, IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define WITH_IDN_OUT_SUPPORT 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + + +# +# IDN support in general +# + +# check if idnkit and libidn2 are not used at the same time +if test "$use_idnkit" != no && test "$use_libidn2" != no; then + as_fn_error $? "idnkit and libidn2 cannot be used at the same time." "$LINENO" 5 +fi +# the IDN support is on +if test "$use_idnkit" != no || test "$use_libidn2" != no; then + +$as_echo "#define WITH_IDN_SUPPORT 1" >>confdefs.h + + if test "$use_libidn2" = no || test "$use_libidn2_out" != no; then + +$as_echo "#define WITH_IDN_OUT_SUPPORT 1" >>confdefs.h + + fi +fi + # # Check whether to build Automated Test Framework unit tests # diff --git a/configure.in b/configure.in index dacc693b17..a4fa556243 100644 --- a/configure.in +++ b/configure.in @@ -4777,49 +4777,34 @@ AC_SUBST(IDNKIT_LIBS) # IDN support using libidn2 # +LIBIDN2_CFLAGS= LIBIDN2_LIBS= AC_ARG_WITH(libidn2, AS_HELP_STRING([--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 - LIBIDN2_LIBS="-lidn2" - ;; -no) - ;; -*) - libidn2_path="$use_libidn2" - LIBIDN2_LIBS="-L$libidn2_path/lib -lidn2" - ;; -esac +AS_CASE([$use_libidn2], + [no],[:], + [yes],[ + LIBIDN2_LIBS="-lidn2" + ], + [*],[ + LIBIDN2_CFLAGS="-I$use_libidn2/include" + LIBIDN2_LIBS="-L$use_libidn2/lib -lidn2" + ]) -if test "$use_libidn2" != no; then - AC_DEFINE(WITH_LIBIDN2, 1, [define if libidn2 support is to be included.]) - saved_cflags="$CFLAGS" - saved_libs="$LIBS" - LIBS="$LIBIDN2_LIBS" - CFLAGS="-I$libidn2_path/include" - - AC_MSG_NOTICE(checking for idn2_to_unicode_8zlz) -AC_TRY_LINK([ -#include -],[ idn2_to_unicode_8zlz(".", NULL, IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT); ], - [AC_MSG_RESULT(yes) - use_libidn2_out=yes], - [AC_MSG_RESULT(no) - use_libidn2_out=no] -) - - STD_CINCLUDES="$STD_CINCLUDES -I$libidn2_path/include" - LIBS="$saved_libs" - CFLAGS="$saved_cflags" -fi -AC_SUBST(LIBIDN2_LIBS) +AS_IF([test "$use_libidn2" != "no"], + [AC_SEARCH_LIBS([idn2_to_ascii_8z], [idn2], + [AC_DEFINE(WITH_LIBIDN2, 1, [define if libidn2 support is to be included.])], + [AC_MSG_ERROR([libidn2 requested, but not found])]) + AC_MSG_CHECKING(whether libidn2 supports idn2_to_unicode_8zlz) + AC_TRY_LINK([#include ], + [idn2_to_unicode_8zlz(".", NULL, IDN2_NONTRANSITIONAL|IDN2_NFC_INPUT);], + [AC_MSG_RESULT(yes) + AC_DEFINE(WITH_IDN_OUT_SUPPORT, 1, [define if IDN output support is to be included.])], + [AC_MSG_RESULT([no])]) + ]) +AC_SUBST([LIBIDN2_CFLAGS]) +AC_SUBST([LIBIDN2_LIBS]) # # IDN support in general From 1c075646f5b7b8e68e482459e7aea5a403c64364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 14 Mar 2018 11:33:09 +0100 Subject: [PATCH 7/9] Enable --with-libidn2 in GitLab CI checks --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9c14d9960e..08a189ddc3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,7 +88,7 @@ stages: - test -w "${CCACHE_DIR}" && export PATH="/usr/lib/ccache:${PATH}" - ./autogen.sh script: - - ./configure --enable-developer --with-libtool --disable-static --with-atf=/usr/local + - ./configure --enable-developer --with-libtool --disable-static --with-atf=/usr/local --with-libidn2 - make -j${PARALLEL_JOBS_BUILD:-1} -k all V=1 artifacts: expire_in: '1 hour' From 8f44ef7d59c04eb443337d0d903820f9f680740c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 14 Mar 2018 12:07:50 +0100 Subject: [PATCH 8/9] Add CHANGES for idn2 support --- CHANGES | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index 2c2e503716..bcdf8f3849 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +4915. [func] Implement IDNA2008 support in dig by adding support + for libidn2. New dig option +idnin has been added, + which allows to process invalid domain names much + like dig without IDN support. libidn2 version 2.0 + or higher is needed for +idnout enabled by default. + 4914. [bug] A bug in zone database reference counting could lead to a crash when multiple versions of a slave zone were transferred from a master in close succession. From e7590c7528229c7bc761a6c69c33dfb69fbaf82f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 14 Mar 2018 13:19:00 +0100 Subject: [PATCH 9/9] Add release notes for IDNA2008 --- doc/arm/notes.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 599a29148b..453fa814fa 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -66,7 +66,9 @@ - None. + BIND now can be compiled against libidn2 library to add + IDNA2008 support. Previously BIND only supported IDNA2003 + using (now obsolete) idnkit-1 library. @@ -120,6 +122,13 @@ that have timed out, in addition to those that respond. [GL #64] + + + dig +noidnin can be used to disable IDN + processing on the input domain name, when BIND is compiled + with IDN support. + +