]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add support for GNU libidn
authorTomas Hozza <thozza@redhat.com>
Wed, 23 Sep 2015 12:37:16 +0000 (14:37 +0200)
committerOndřej Surý <ondrej@sury.org>
Sat, 17 Mar 2018 13:13:47 +0000 (13:13 +0000)
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 <thozza@redhat.com>
bin/dig/Makefile.in
bin/dig/dighost.c
configure.in

index 46a4cf60f7f3a8fa986b76e1e46cc08fb580c130..72e84f21dac07f86fa2246b091fc6e5a31863de4 100644 (file)
@@ -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 =
 
index 508c620e67893b0afb34f27984395179ad54eab4..9510506a8421d277bb1d4a6d4efb22f5086e08c2 100644 (file)
 #include <unistd.h>
 #include <string.h>
 #include <limits.h>
+#include <errno.h>
 
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
 #endif
 
-#ifdef WITH_IDN
+#ifdef WITH_IDN_SUPPORT
+#ifdef WITH_IDNKIT
 #include <idn/result.h>
 #include <idn/log.h>
 #include <idn/resconf.h>
 #include <idn/api.h>
 #endif
 
+#ifdef WITH_LIBIDN
+#include <idna.h>
+#include <stringprep.h>
+#endif
+#endif /* WITH_IDN_SUPPORT */
+
 #include <dns/byaddr.h>
 #include <dns/fixedname.h>
 #include <dns/log.h>
@@ -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);
-
-#define MAXDLEN                256
-int  idnoptions        = 0;
+#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
+
+#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");
-       }
-       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
+               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));
+       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 */
index f2acb659fbdeae9f445495d9a8836e218526f0fc..228af0b4bcbff5e14220fc84495750de75451965 100644 (file)
@@ -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