IDN support in dig and host utilities
Adam Tkac
atkac at redhat.com
Tue Dec 11 17:08:18 UTC 2007
Hi,
some time ago I tried add IDN support to dig and host utilities in
Fedora. After investigation I've found that idnkit which is shipped
in contrib subdirectory is completely unusable. It's old source,
project is not maintained (not sure) and I'm not able to compile it
without heavy patching on modern system. So I've written small patch which
adds support to use libidn (http://www.gnu.org/software/libidn/) which
is good alternative to idnkit. What is your opinion about that? Would
it be possible include it to main source?
Regards, Adam
--
Adam Tkac, Red Hat, Inc.
-------------- next part --------------
--- dighost.c.libidn 2007-06-19 01:47:17.000000000 +0200
+++ dighost.c 2007-12-11 17:49:45.000000000 +0100
@@ -44,6 +44,11 @@
#include <idn/api.h>
#endif
+#ifdef WITH_LIBIDN
+#include <stringprep.h>
+#include <idna.h>
+#endif
+
#include <dns/byaddr.h>
#ifdef DIG_SIGCHASE
#include <dns/dnssec.h>
@@ -147,6 +152,14 @@
int idnoptions = 0;
#endif
+#ifdef WITH_LIBIDN
+static isc_result_t libidn_locale_to_utf8 (const char* from, char *to);
+static isc_result_t libidn_utf8_to_ascii (const char* from, char *to);
+static isc_result_t output_filter (isc_buffer_t *buffer,
+ unsigned int used_org,
+ isc_boolean_t absolute);
+#endif
+
/*%
* Exit Codes:
*
@@ -1002,6 +1015,9 @@
setup_system(void) {
dig_searchlist_t *domain = NULL;
lwres_result_t lwresult;
+#ifdef WITH_LIBIDN
+ isc_result_t result;
+#endif
debug("setup_system()");
@@ -1050,8 +1066,15 @@
#ifdef WITH_IDN
initialize_idn();
+
+#endif
+#ifdef WITH_LIBIDN
+ result = dns_name_settotextfilter(output_filter);
+ check_result(result, "dns_name_settotextfilter");
+#ifdef HAVE_SETLOCALE
+ setlocale (LC_ALL, "");
+#endif
#endif
-
if (keyfile[0] != 0)
setup_file_key();
else if (keysecret[0] != 0)
@@ -1740,12 +1763,14 @@
idn_result_t mr;
char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME];
#endif
+#ifdef WITH_LIBIDN
+ char utf8_str[MXNAME], utf8_name[MXNAME], ascii_name[MXNAME];
+#endif
-#ifdef WITH_IDN
+#if defined (WITH_IDN) || defined (WITH_LIBIDN)
result = dns_name_settotextfilter(output_filter);
check_result(result, "dns_name_settotextfilter");
#endif
-
REQUIRE(lookup != NULL);
INSIST(!free_now);
@@ -1782,6 +1807,14 @@
mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname,
utf8_textname, sizeof(utf8_textname));
idn_check_result(mr, "convert textname to UTF-8");
+#elif defined (WITH_LIBIDN)
+ result = libidn_locale_to_utf8 (lookup->textname, utf8_str);
+ check_result (result, "convert textname to UTF-8");
+ len = strlen (utf8_str);
+ if (len < MXNAME)
+ (void) strcpy (utf8_name, utf8_str);
+ else
+ fatal ("Too long name");
#endif
/*
@@ -1794,15 +1827,11 @@
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;
- }
+#elif defined (WITH_LIBIDN)
+ if ((count_dots(utf8_name) >= ndots) || !usesearch) {
#else
if ((count_dots(lookup->textname) >= ndots) || !usesearch) {
+#endif
lookup->origin = NULL; /* Force abs lookup */
lookup->done_as_is = ISC_TRUE;
lookup->need_search = usesearch;
@@ -1810,7 +1839,6 @@
lookup->origin = ISC_LIST_HEAD(search_list);
lookup->need_search = ISC_FALSE;
}
-#endif
}
#ifdef WITH_IDN
@@ -1827,6 +1855,17 @@
IDN_IDNCONV | IDN_LENCHECK, utf8_textname,
idn_textname, sizeof(idn_textname));
idn_check_result(mr, "convert UTF-8 textname to IDN encoding");
+#elif defined (WITH_LIBIDN)
+ if (lookup->origin != NULL) {
+ result = libidn_locale_to_utf8 (lookup->origin->origin, utf8_str);
+ check_result (result, "convert origin to UTF-8");
+ if (len + strlen (utf8_str) < MXNAME)
+ (void) strcpy (utf8_name + len, utf8_str);
+ else
+ fatal ("Too long name + origin");
+ }
+
+ result = libidn_utf8_to_ascii (utf8_name, ascii_name);
#else
if (lookup->origin != NULL) {
debug("trying origin %s", lookup->origin->origin);
@@ -1883,6 +1922,14 @@
dns_rootname,
ISC_FALSE,
&lookup->namebuf);
+#elif defined (WITH_LIBIDN)
+ len = strlen (ascii_name);
+ isc_buffer_init(&b, ascii_name, len);
+ isc_buffer_add(&b, len);
+ result = dns_name_fromtext(lookup->name, &b,
+ dns_rootname,
+ ISC_FALSE,
+ &lookup->namebuf);
#else
len = strlen(lookup->textname);
isc_buffer_init(&b, lookup->textname, len);
@@ -3310,7 +3357,7 @@
void * ptr;
dig_message_t *chase_msg;
#endif
-#ifdef WITH_IDN
+#if defined (WITH_IDN) || defined (WITH_LIBIDN)
isc_result_t result;
#endif
@@ -3349,6 +3396,10 @@
result = dns_name_settotextfilter(NULL);
check_result(result, "dns_name_settotextfilter");
#endif
+#ifdef WITH_LIBIDN
+ result = dns_name_settotextfilter (NULL);
+ check_result(result, "clearing dns_name_settotextfilter");
+#endif
dns_name_destroy();
if (commctx != NULL) {
@@ -3525,6 +3576,88 @@
}
}
#endif /* WITH_IDN */
+#ifdef WITH_LIBIDN
+static isc_result_t
+libidn_locale_to_utf8 (const char *from, char *to) {
+ char *utf8_str;
+
+ debug ("libidn_locale_to_utf8");
+ utf8_str = stringprep_locale_to_utf8 (from);
+ if (utf8_str != NULL) {
+ (void) strcpy (to, utf8_str);
+ free (utf8_str);
+ return ISC_R_SUCCESS;
+ }
+
+ debug ("libidn_locale_to_utf8: failure");
+ return ISC_R_FAILURE;
+}
+static isc_result_t
+libidn_utf8_to_ascii (const char *from, char *to) {
+ char *ascii;
+ int iresult;
+
+ debug ("libidn_utf8_to_ascii");
+ iresult = idna_to_ascii_8z (from, &ascii, 0);
+ if (iresult != IDNA_SUCCESS) {
+ debug ("idna_to_ascii_8z: %s", idna_strerror (iresult));
+ return ISC_R_FAILURE;
+ }
+
+ (void) strcpy (to, ascii);
+ free (ascii);
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+output_filter (isc_buffer_t *buffer, unsigned int used_org,
+ isc_boolean_t absolute) {
+
+ char tmp1[MXNAME], *tmp2;
+ size_t fromlen, tolen;
+ isc_boolean_t end_with_dot;
+ int iresult;
+
+ debug ("output_filter");
+
+ fromlen = isc_buffer_usedlength (buffer) - used_org;
+ if (fromlen >= MXNAME)
+ return ISC_R_SUCCESS;
+ memcpy (tmp1, (char *) isc_buffer_base (buffer) + used_org, fromlen);
+ end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE;
+ if (absolute && !end_with_dot) {
+ fromlen++;
+ if (fromlen >= MXNAME)
+ return ISC_R_SUCCESS;
+ tmp1[fromlen - 1] = '.';
+ }
+ tmp1[fromlen] = '\0';
+
+ iresult = idna_to_unicode_8z8z (tmp1, &tmp2, 0);
+ if (iresult != IDNA_SUCCESS) {
+ debug ("output_filter: %s", idna_strerror (iresult));
+ return ISC_R_SUCCESS;
+ }
+
+ (void) strcpy (tmp1, tmp2);
+ free (tmp2);
+
+ tolen = strlen (tmp1);
+ if (absolute && !end_with_dot && tmp1[tolen - 1] == '.')
+ tolen--;
+
+ if (isc_buffer_length (buffer) < used_org + tolen)
+ return ISC_R_NOSPACE;
+
+ debug ("%s", tmp1);
+
+ isc_buffer_subtract (buffer, isc_buffer_usedlength (buffer) - used_org);
+ memcpy (isc_buffer_used (buffer), tmp1, tolen);
+ isc_buffer_add (buffer, tolen);
+
+ return ISC_R_SUCCESS;
+}
+#endif /* WITH_LIBIDN*/
#ifdef DIG_SIGCHASE
void
More information about the bind-workers
mailing list