#include <alloca.h>
#include <errno.h>
#include <netdb.h>
+#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <bits/libc-lock.h>
+#ifdef HAVE_LIBIDN
+# include <libidn/idna.h>
+extern int __idna_to_unicode_lzlz (const char *input, char **output,
+ int flags);
+#endif
+
#ifndef min
# define min(x,y) (((x) > (y)) ? (y) : (x))
#endif /* min */
+libc_freeres_ptr (static char *domain);
+
static char *
internal_function
nrl_domainname (void)
{
- static char *domain;
static int not_first;
if (! not_first)
&herror))
{
if (herror == NETDB_INTERNAL && errno == ERANGE)
- {
- tmpbuflen *= 2;
- tmpbuf = alloca (tmpbuflen);
- }
+ tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
else
break;
}
/* The name contains no domain information. Use the name
now to get more information. */
while (__gethostname (tmpbuf, tmpbuflen))
- {
- tmpbuflen *= 2;
- tmpbuf = alloca (tmpbuflen);
- }
+ tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
if ((c = strchr (tmpbuf, '.')))
domain = __strdup (++c);
&h, &herror))
{
if (herror == NETDB_INTERNAL && errno == ERANGE)
- {
- tmpbuflen *= 2;
- tmpbuf = alloca (tmpbuflen);
- }
+ tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+ 2 * tmpbuflen);
else
break;
}
tmpbuflen, &h, &herror))
{
if (herror == NETDB_INTERNAL && errno == ERANGE)
- {
- tmpbuflen *= 2;
- tmpbuf = alloca (tmpbuflen);
- }
+ tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+ 2 * tmpbuflen);
else
break;
}
struct hostent th;
int ok = 0;
- if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
+ if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
+#ifdef HAVE_LIBIDN
+ |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
+#endif
+ ))
return EAI_BADFLAGS;
if (sa == NULL || addrlen < sizeof (sa_family_t))
if (herrno == NETDB_INTERNAL)
{
if (errno == ERANGE)
- {
- tmpbuflen *= 2;
- tmpbuf = alloca (tmpbuflen);
- }
+ tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+ 2 * tmpbuflen);
else
{
__set_h_errno (herrno);
&h, &herrno))
{
if (errno == ERANGE)
- {
- tmpbuflen *= 2;
- tmpbuf = alloca (tmpbuflen);
- }
+ tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+ 2 * tmpbuflen);
else
{
break;
&& (c = nrl_domainname ())
&& (c = strstr (h->h_name, c))
&& (c != h->h_name) && (*(--c) == '.'))
+ /* Terminate the string after the prefix. */
+ *c = '\0';
+
+#ifdef HAVE_LIBIDN
+ /* If requested, convert from the IDN format. */
+ if (flags & NI_IDN)
{
- strncpy (host, h->h_name,
- min(hostlen, (size_t) (c - h->h_name)));
- host[min(hostlen - 1, (size_t) (c - h->h_name))]
- = '\0';
- ok = 1;
- }
- else
- {
- strncpy (host, h->h_name, hostlen);
- ok = 1;
+ int idn_flags = 0;
+ if (flags & NI_IDN_ALLOW_UNASSIGNED)
+ idn_flags |= IDNA_ALLOW_UNASSIGNED;
+ if (flags & NI_IDN_USE_STD3_ASCII_RULES)
+ idn_flags |= IDNA_USE_STD3_ASCII_RULES;
+
+ char *out;
+ int rc = __idna_to_unicode_lzlz (h->h_name, &out,
+ idn_flags);
+ if (rc != IDNA_SUCCESS)
+ {
+ if (rc == IDNA_MALLOC_ERROR)
+ return EAI_MEMORY;
+ if (rc == IDNA_DLOPEN_ERROR)
+ return EAI_SYSTEM;
+ return EAI_IDN_ENCODE;
+ }
+
+ if (out != h->h_name)
+ {
+ h->h_name = strdupa (out);
+ free (out);
+ }
}
+#endif
+
+ size_t len = strlen (h->h_name) + 1;
+ if (len > hostlen)
+ return EAI_OVERFLOW;
+
+ memcpy (host, h->h_name, len);
+
+ ok = 1;
}
}
if (herrno == NETDB_INTERNAL)
{
if (errno == ERANGE)
- {
- tmpbuflen *= 2;
- tmpbuf = __alloca (tmpbuflen);
- }
+ tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+ 2 * tmpbuflen);
else
{
__set_errno (serrno);
break;
}
}
- __snprintf (serv, servlen, "%d",
- ntohs (((const struct sockaddr_in *) sa)->sin_port));
+
+ if (__snprintf (serv, servlen, "%d",
+ ntohs (((const struct sockaddr_in *) sa)->sin_port))
+ + 1 > servlen)
+ return EAI_OVERFLOW;
+
break;
case AF_LOCAL:
errno = serrno;
return 0;
}
+libc_hidden_def (getnameinfo)