Add a testase for BZ #14602
[glibc.git] / inet / getnameinfo.c
blob436604b756482f3b45793e8111af4a91f49bc85a
1 /* The Inner Net License, Version 2.00
3 The author(s) grant permission for redistribution and use in source and
4 binary forms, with or without modification, of the software and documentation
5 provided that the following conditions are met:
7 0. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
10 way or form.
11 1. All terms of the all other applicable copyrights and licenses must be
12 followed.
13 2. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
15 3. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 4. [The copyright holder has authorized the removal of this clause.]
19 5. Neither the name(s) of the author(s) nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 If these license terms cause you a real problem, contact the author. */
36 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
38 #include <alloca.h>
39 #include <errno.h>
40 #include <netdb.h>
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <arpa/inet.h>
47 #include <net/if.h>
48 #include <netinet/in.h>
49 #include <sys/param.h>
50 #include <sys/socket.h>
51 #include <sys/types.h>
52 #include <sys/un.h>
53 #include <sys/utsname.h>
54 #include <bits/libc-lock.h>
56 #ifdef HAVE_LIBIDN
57 # include <libidn/idna.h>
58 extern int __idna_to_unicode_lzlz (const char *input, char **output,
59 int flags);
60 #endif
62 #ifndef min
63 # define min(x,y) (((x) > (y)) ? (y) : (x))
64 #endif /* min */
66 libc_freeres_ptr (static char *domain);
69 static char *
70 internal_function
71 nrl_domainname (void)
73 static int not_first;
75 if (! not_first)
77 __libc_lock_define_initialized (static, lock);
78 __libc_lock_lock (lock);
80 if (! not_first)
82 char *c;
83 struct hostent *h, th;
84 size_t tmpbuflen = 1024;
85 char *tmpbuf = alloca (tmpbuflen);
86 int herror;
88 not_first = 1;
90 while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
91 &herror))
93 if (herror == NETDB_INTERNAL && errno == ERANGE)
94 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
95 else
96 break;
99 if (h && (c = strchr (h->h_name, '.')))
100 domain = __strdup (++c);
101 else
103 /* The name contains no domain information. Use the name
104 now to get more information. */
105 while (__gethostname (tmpbuf, tmpbuflen))
106 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
108 if ((c = strchr (tmpbuf, '.')))
109 domain = __strdup (++c);
110 else
112 /* We need to preserve the hostname. */
113 const char *hstname = strdupa (tmpbuf);
115 while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
116 &h, &herror))
118 if (herror == NETDB_INTERNAL && errno == ERANGE)
119 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
120 2 * tmpbuflen);
121 else
122 break;
125 if (h && (c = strchr(h->h_name, '.')))
126 domain = __strdup (++c);
127 else
129 struct in_addr in_addr;
131 in_addr.s_addr = htonl (INADDR_LOOPBACK);
133 while (__gethostbyaddr_r ((const char *) &in_addr,
134 sizeof (struct in_addr),
135 AF_INET, &th, tmpbuf,
136 tmpbuflen, &h, &herror))
138 if (herror == NETDB_INTERNAL && errno == ERANGE)
139 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
140 2 * tmpbuflen);
141 else
142 break;
145 if (h && (c = strchr (h->h_name, '.')))
146 domain = __strdup (++c);
152 __libc_lock_unlock (lock);
155 return domain;
160 getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
161 socklen_t hostlen, char *serv, socklen_t servlen,
162 int flags)
164 int serrno = errno;
165 int tmpbuflen = 1024;
166 int herrno;
167 char *tmpbuf = alloca (tmpbuflen);
168 struct hostent th;
169 int ok = 0;
171 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
172 #ifdef HAVE_LIBIDN
173 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
174 #endif
176 return EAI_BADFLAGS;
178 if (sa == NULL || addrlen < sizeof (sa_family_t))
179 return EAI_FAMILY;
181 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
182 return EAI_NONAME;
184 switch (sa->sa_family)
186 case AF_LOCAL:
187 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
188 return EAI_FAMILY;
189 break;
190 case AF_INET:
191 if (addrlen < sizeof (struct sockaddr_in))
192 return EAI_FAMILY;
193 break;
194 case AF_INET6:
195 if (addrlen < sizeof (struct sockaddr_in6))
196 return EAI_FAMILY;
197 break;
198 default:
199 return EAI_FAMILY;
202 if (host != NULL && hostlen > 0)
203 switch (sa->sa_family)
205 case AF_INET:
206 case AF_INET6:
207 if (!(flags & NI_NUMERICHOST))
209 struct hostent *h = NULL;
210 if (sa->sa_family == AF_INET6)
212 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
213 sizeof(struct in6_addr),
214 AF_INET6, &th, tmpbuf, tmpbuflen,
215 &h, &herrno))
216 if (herrno == NETDB_INTERNAL && errno == ERANGE)
217 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
218 else
219 break;
221 else
223 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
224 sizeof(struct in_addr), AF_INET,
225 &th, tmpbuf, tmpbuflen,
226 &h, &herrno))
227 if (herrno == NETDB_INTERNAL && errno == ERANGE)
228 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
229 else
230 break;
233 if (h == NULL)
235 if (herrno == NETDB_INTERNAL)
237 __set_h_errno (herrno);
238 return EAI_SYSTEM;
240 if (herrno == TRY_AGAIN)
242 __set_h_errno (herrno);
243 return EAI_AGAIN;
247 if (h)
249 char *c;
250 if ((flags & NI_NOFQDN)
251 && (c = nrl_domainname ())
252 && (c = strstr (h->h_name, c))
253 && (c != h->h_name) && (*(--c) == '.'))
254 /* Terminate the string after the prefix. */
255 *c = '\0';
257 #ifdef HAVE_LIBIDN
258 /* If requested, convert from the IDN format. */
259 if (flags & NI_IDN)
261 int idn_flags = 0;
262 if (flags & NI_IDN_ALLOW_UNASSIGNED)
263 idn_flags |= IDNA_ALLOW_UNASSIGNED;
264 if (flags & NI_IDN_USE_STD3_ASCII_RULES)
265 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
267 char *out;
268 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
269 idn_flags);
270 if (rc != IDNA_SUCCESS)
272 if (rc == IDNA_MALLOC_ERROR)
273 return EAI_MEMORY;
274 if (rc == IDNA_DLOPEN_ERROR)
275 return EAI_SYSTEM;
276 return EAI_IDN_ENCODE;
279 if (out != h->h_name)
281 h->h_name = strdupa (out);
282 free (out);
285 #endif
287 size_t len = strlen (h->h_name) + 1;
288 if (len > hostlen)
289 return EAI_OVERFLOW;
291 memcpy (host, h->h_name, len);
293 ok = 1;
297 if (!ok)
299 if (flags & NI_NAMEREQD)
301 __set_errno (serrno);
302 return EAI_NONAME;
304 else
306 const char *c;
307 if (sa->sa_family == AF_INET6)
309 const struct sockaddr_in6 *sin6p;
310 uint32_t scopeid;
312 sin6p = (const struct sockaddr_in6 *) sa;
314 c = inet_ntop (AF_INET6,
315 (const void *) &sin6p->sin6_addr, host, hostlen);
316 scopeid = sin6p->sin6_scope_id;
317 if (scopeid != 0)
319 /* Buffer is >= IFNAMSIZ+1. */
320 char scopebuf[IFNAMSIZ + 1];
321 char *scopeptr;
322 int ni_numericscope = 0;
323 size_t real_hostlen = __strnlen (host, hostlen);
324 size_t scopelen = 0;
326 scopebuf[0] = SCOPE_DELIMITER;
327 scopebuf[1] = '\0';
328 scopeptr = &scopebuf[1];
330 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
331 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
333 if (if_indextoname (scopeid, scopeptr) == NULL)
334 ++ni_numericscope;
335 else
336 scopelen = strlen (scopebuf);
338 else
339 ++ni_numericscope;
341 if (ni_numericscope)
342 scopelen = 1 + __snprintf (scopeptr,
343 (scopebuf
344 + sizeof scopebuf
345 - scopeptr),
346 "%u", scopeid);
348 if (real_hostlen + scopelen + 1 > hostlen)
349 /* Signal the buffer is too small. This is
350 what inet_ntop does. */
351 c = NULL;
352 else
353 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
356 else
357 c = inet_ntop (AF_INET,
358 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
359 host, hostlen);
360 if (c == NULL)
361 return EAI_OVERFLOW;
363 ok = 1;
365 break;
367 case AF_LOCAL:
368 if (!(flags & NI_NUMERICHOST))
370 struct utsname utsname;
372 if (!uname (&utsname))
374 strncpy (host, utsname.nodename, hostlen);
375 break;
379 if (flags & NI_NAMEREQD)
381 __set_errno (serrno);
382 return EAI_NONAME;
385 strncpy (host, "localhost", hostlen);
386 break;
388 default:
389 return EAI_FAMILY;
392 if (serv && (servlen > 0))
393 switch (sa->sa_family)
395 case AF_INET:
396 case AF_INET6:
397 if (!(flags & NI_NUMERICSERV))
399 struct servent *s, ts;
400 int e;
401 while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
402 ((flags & NI_DGRAM)
403 ? "udp" : "tcp"),
404 &ts, tmpbuf, tmpbuflen, &s)))
406 if (e == ERANGE)
407 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
408 else
409 break;
411 if (s)
413 strncpy (serv, s->s_name, servlen);
414 break;
418 if (__snprintf (serv, servlen, "%d",
419 ntohs (((const struct sockaddr_in *) sa)->sin_port))
420 + 1 > servlen)
421 return EAI_OVERFLOW;
423 break;
425 case AF_LOCAL:
426 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
427 break;
430 if (host && (hostlen > 0))
431 host[hostlen-1] = 0;
432 if (serv && (servlen > 0))
433 serv[servlen-1] = 0;
434 errno = serrno;
435 return 0;
437 libc_hidden_def (getnameinfo)