summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--resolv/netdb.h1
-rw-r--r--sysdeps/posix/getaddrinfo.c48
2 files changed, 44 insertions, 5 deletions
diff --git a/resolv/netdb.h b/resolv/netdb.h
index 5aaa387166..238510f0e4 100644
--- a/resolv/netdb.h
+++ b/resolv/netdb.h
@@ -577,6 +577,7 @@ struct gaicb
# define AI_IDN 0x0040 /* IDN encode input (assuming it is encoded
in the current locale's character set)
before looking it up. */
+# define AI_CANONIDN 0x0080 /* Translate canonical name from IDN format. */
# endif
/* Error values for `getaddrinfo' function. */
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 2b6f0ba0ac..4597feac79 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -55,8 +55,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <nsswitch.h>
#include <not-cancel.h>
+#ifdef HAVE_LIBIDN
extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
-#define IDNA_SUCCESS 0
+extern int __idna_to_unicode_lzlz (const char *input, char **output,
+ int flags);
+# include <libidn/idna.h>
+#endif
#define GAIH_OKIFUNSPEC 0x0100
#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
@@ -548,9 +552,20 @@ gaih_inet (const char *name, const struct gaih_service *service,
char *p = NULL;
rc = __idna_to_ascii_lz (name, &p, 0);
if (rc != IDNA_SUCCESS)
- return -EAI_IDN_ENCODE;
- name = strdupa (p);
- free (p);
+ {
+ if (rc == IDNA_MALLOC_ERROR)
+ return -EAI_MEMORY;
+ if (rc == IDNA_DLOPEN_ERROR)
+ return -EAI_SYSTEM;
+ return -EAI_IDN_ENCODE;
+ }
+ /* In case the output string is the same as the input string
+ no new string has been allocated. */
+ if (p != name)
+ {
+ name = strdupa (p);
+ free (p);
+ }
}
#endif
@@ -820,6 +835,29 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (c == NULL)
return GAIH_OKIFUNSPEC | -EAI_NONAME;
+#ifdef HAVE_LIBIDN
+ if (req->ai_flags & AI_CANONIDN)
+ {
+ char *out;
+ int rc = __idna_to_unicode_lzlz (c, &out, 0);
+ if (rc != IDNA_SUCCESS)
+ {
+ if (rc == IDNA_MALLOC_ERROR)
+ return -EAI_MEMORY;
+ if (rc == IDNA_DLOPEN_ERROR)
+ return -EAI_SYSTEM;
+ return -EAI_IDN_ENCODE;
+ }
+ /* In case the output string is the same as the input
+ string no new string has been allocated. */
+ if (out != c)
+ {
+ c = strdupa (out);
+ free (out);
+ }
+ }
+#endif
+
namelen = strlen (c) + 1;
}
else
@@ -1268,7 +1306,7 @@ getaddrinfo (const char *name, const char *service,
if (hints->ai_flags
& ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED
#ifdef HAVE_LIBIDN
- |AI_IDN
+ |AI_IDN|AI_CANONIDN
#endif
|AI_ALL))
return EAI_BADFLAGS;