Add a test for BZ #15674
[glibc.git] / inet / getnameinfo.c
blobce54fe42a843ec05f1cfc91d4a05720872e1bf20
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 <stdint.h>
47 #include <arpa/inet.h>
48 #include <net/if.h>
49 #include <netinet/in.h>
50 #include <sys/param.h>
51 #include <sys/socket.h>
52 #include <sys/types.h>
53 #include <sys/un.h>
54 #include <sys/utsname.h>
55 #include <bits/libc-lock.h>
57 #ifdef HAVE_LIBIDN
58 # include <libidn/idna.h>
59 extern int __idna_to_unicode_lzlz (const char *input, char **output,
60 int flags);
61 #endif
63 #ifndef min
64 # define min(x,y) (((x) > (y)) ? (y) : (x))
65 #endif /* min */
67 libc_freeres_ptr (static char *domain);
70 static char *
71 internal_function
72 nrl_domainname (void)
74 static int not_first;
76 if (! not_first)
78 __libc_lock_define_initialized (static, lock);
79 __libc_lock_lock (lock);
81 if (! not_first)
83 char *c;
84 struct hostent *h, th;
85 size_t tmpbuflen = 1024;
86 char *tmpbuf = alloca (tmpbuflen);
87 int herror;
89 not_first = 1;
91 while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
92 &herror))
94 if (herror == NETDB_INTERNAL && errno == ERANGE)
95 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
96 else
97 break;
100 if (h && (c = strchr (h->h_name, '.')))
101 domain = __strdup (++c);
102 else
104 /* The name contains no domain information. Use the name
105 now to get more information. */
106 while (__gethostname (tmpbuf, tmpbuflen))
107 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
109 if ((c = strchr (tmpbuf, '.')))
110 domain = __strdup (++c);
111 else
113 /* We need to preserve the hostname. */
114 const char *hstname = strdupa (tmpbuf);
116 while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
117 &h, &herror))
119 if (herror == NETDB_INTERNAL && errno == ERANGE)
120 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
121 2 * tmpbuflen);
122 else
123 break;
126 if (h && (c = strchr(h->h_name, '.')))
127 domain = __strdup (++c);
128 else
130 struct in_addr in_addr;
132 in_addr.s_addr = htonl (INADDR_LOOPBACK);
134 while (__gethostbyaddr_r ((const char *) &in_addr,
135 sizeof (struct in_addr),
136 AF_INET, &th, tmpbuf,
137 tmpbuflen, &h, &herror))
139 if (herror == NETDB_INTERNAL && errno == ERANGE)
140 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
141 2 * tmpbuflen);
142 else
143 break;
146 if (h && (c = strchr (h->h_name, '.')))
147 domain = __strdup (++c);
153 __libc_lock_unlock (lock);
156 return domain;
161 getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
162 socklen_t hostlen, char *serv, socklen_t servlen,
163 int flags)
165 int serrno = errno;
166 int tmpbuflen = 1024;
167 int herrno;
168 char *tmpbuf = alloca (tmpbuflen);
169 struct hostent th;
170 int ok = 0;
172 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
173 #ifdef HAVE_LIBIDN
174 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
175 #endif
177 return EAI_BADFLAGS;
179 if (sa == NULL || addrlen < sizeof (sa_family_t))
180 return EAI_FAMILY;
182 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
183 return EAI_NONAME;
185 switch (sa->sa_family)
187 case AF_LOCAL:
188 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
189 return EAI_FAMILY;
190 break;
191 case AF_INET:
192 if (addrlen < sizeof (struct sockaddr_in))
193 return EAI_FAMILY;
194 break;
195 case AF_INET6:
196 if (addrlen < sizeof (struct sockaddr_in6))
197 return EAI_FAMILY;
198 break;
199 default:
200 return EAI_FAMILY;
203 if (host != NULL && hostlen > 0)
204 switch (sa->sa_family)
206 case AF_INET:
207 case AF_INET6:
208 if (!(flags & NI_NUMERICHOST))
210 struct hostent *h = NULL;
211 if (sa->sa_family == AF_INET6)
213 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
214 sizeof(struct in6_addr),
215 AF_INET6, &th, tmpbuf, tmpbuflen,
216 &h, &herrno))
217 if (herrno == NETDB_INTERNAL && errno == ERANGE)
218 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
219 else
220 break;
222 else
224 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
225 sizeof(struct in_addr), AF_INET,
226 &th, tmpbuf, tmpbuflen,
227 &h, &herrno))
228 if (herrno == NETDB_INTERNAL && errno == ERANGE)
229 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
230 else
231 break;
234 if (h == NULL)
236 if (herrno == NETDB_INTERNAL)
238 __set_h_errno (herrno);
239 return EAI_SYSTEM;
241 if (herrno == TRY_AGAIN)
243 __set_h_errno (herrno);
244 return EAI_AGAIN;
248 if (h)
250 char *c;
251 if ((flags & NI_NOFQDN)
252 && (c = nrl_domainname ())
253 && (c = strstr (h->h_name, c))
254 && (c != h->h_name) && (*(--c) == '.'))
255 /* Terminate the string after the prefix. */
256 *c = '\0';
258 #ifdef HAVE_LIBIDN
259 /* If requested, convert from the IDN format. */
260 if (flags & NI_IDN)
262 int idn_flags = 0;
263 if (flags & NI_IDN_ALLOW_UNASSIGNED)
264 idn_flags |= IDNA_ALLOW_UNASSIGNED;
265 if (flags & NI_IDN_USE_STD3_ASCII_RULES)
266 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
268 char *out;
269 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
270 idn_flags);
271 if (rc != IDNA_SUCCESS)
273 if (rc == IDNA_MALLOC_ERROR)
274 return EAI_MEMORY;
275 if (rc == IDNA_DLOPEN_ERROR)
276 return EAI_SYSTEM;
277 return EAI_IDN_ENCODE;
280 if (out != h->h_name)
282 h->h_name = strdupa (out);
283 free (out);
286 #endif
288 size_t len = strlen (h->h_name) + 1;
289 if (len > hostlen)
290 return EAI_OVERFLOW;
292 memcpy (host, h->h_name, len);
294 ok = 1;
298 if (!ok)
300 if (flags & NI_NAMEREQD)
302 __set_errno (serrno);
303 return EAI_NONAME;
305 else
307 const char *c;
308 if (sa->sa_family == AF_INET6)
310 const struct sockaddr_in6 *sin6p;
311 uint32_t scopeid;
313 sin6p = (const struct sockaddr_in6 *) sa;
315 c = inet_ntop (AF_INET6,
316 (const void *) &sin6p->sin6_addr, host, hostlen);
317 scopeid = sin6p->sin6_scope_id;
318 if (scopeid != 0)
320 /* Buffer is >= IFNAMSIZ+1. */
321 char scopebuf[IFNAMSIZ + 1];
322 char *scopeptr;
323 int ni_numericscope = 0;
324 size_t real_hostlen = __strnlen (host, hostlen);
325 size_t scopelen = 0;
327 scopebuf[0] = SCOPE_DELIMITER;
328 scopebuf[1] = '\0';
329 scopeptr = &scopebuf[1];
331 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
332 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
334 if (if_indextoname (scopeid, scopeptr) == NULL)
335 ++ni_numericscope;
336 else
337 scopelen = strlen (scopebuf);
339 else
340 ++ni_numericscope;
342 if (ni_numericscope)
343 scopelen = 1 + __snprintf (scopeptr,
344 (scopebuf
345 + sizeof scopebuf
346 - scopeptr),
347 "%u", scopeid);
349 if (real_hostlen + scopelen + 1 > hostlen)
350 /* Signal the buffer is too small. This is
351 what inet_ntop does. */
352 c = NULL;
353 else
354 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
357 else
358 c = inet_ntop (AF_INET,
359 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
360 host, hostlen);
361 if (c == NULL)
362 return EAI_OVERFLOW;
364 ok = 1;
366 break;
368 case AF_LOCAL:
369 if (!(flags & NI_NUMERICHOST))
371 struct utsname utsname;
373 if (!uname (&utsname))
375 strncpy (host, utsname.nodename, hostlen);
376 break;
380 if (flags & NI_NAMEREQD)
382 __set_errno (serrno);
383 return EAI_NONAME;
386 strncpy (host, "localhost", hostlen);
387 break;
389 default:
390 return EAI_FAMILY;
393 if (serv && (servlen > 0))
394 switch (sa->sa_family)
396 case AF_INET:
397 case AF_INET6:
398 if (!(flags & NI_NUMERICSERV))
400 struct servent *s, ts;
401 int e;
402 while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
403 ((flags & NI_DGRAM)
404 ? "udp" : "tcp"),
405 &ts, tmpbuf, tmpbuflen, &s)))
407 if (e == ERANGE)
408 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
409 else
410 break;
412 if (s)
414 strncpy (serv, s->s_name, servlen);
415 break;
419 if (__snprintf (serv, servlen, "%d",
420 ntohs (((const struct sockaddr_in *) sa)->sin_port))
421 + 1 > servlen)
422 return EAI_OVERFLOW;
424 break;
426 case AF_LOCAL:
427 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
428 break;
431 if (host && (hostlen > 0))
432 host[hostlen-1] = 0;
433 if (serv && (servlen > 0))
434 serv[servlen-1] = 0;
435 errno = serrno;
436 return 0;
438 libc_hidden_def (getnameinfo)