Add envz_remove to the libc manual
[glibc.git] / inet / getnameinfo.c
blob0126f2032655e5bb4d610c9eddf22ae10ee54cf3
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 <errno.h>
39 #include <netdb.h>
40 #include <stddef.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <stdint.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>
55 #include <scratch_buffer.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 int herror;
86 struct scratch_buffer tmpbuf;
88 scratch_buffer_init (&tmpbuf);
89 not_first = 1;
91 while (__gethostbyname_r ("localhost", &th,
92 tmpbuf.data, tmpbuf.length,
93 &h, &herror))
95 if (herror == NETDB_INTERNAL && errno == ERANGE)
97 if (!scratch_buffer_grow (&tmpbuf))
98 goto done;
100 else
101 break;
104 if (h && (c = strchr (h->h_name, '.')))
105 domain = __strdup (++c);
106 else
108 /* The name contains no domain information. Use the name
109 now to get more information. */
110 while (__gethostname (tmpbuf.data, tmpbuf.length))
111 if (!scratch_buffer_grow (&tmpbuf))
112 goto done;
114 if ((c = strchr (tmpbuf.data, '.')))
115 domain = __strdup (++c);
116 else
118 /* We need to preserve the hostname. */
119 const char *hstname = strdupa (tmpbuf.data);
121 while (__gethostbyname_r (hstname, &th,
122 tmpbuf.data, tmpbuf.length,
123 &h, &herror))
125 if (herror == NETDB_INTERNAL && errno == ERANGE)
127 if (!scratch_buffer_grow (&tmpbuf))
128 goto done;
130 else
131 break;
134 if (h && (c = strchr(h->h_name, '.')))
135 domain = __strdup (++c);
136 else
138 struct in_addr in_addr;
140 in_addr.s_addr = htonl (INADDR_LOOPBACK);
142 while (__gethostbyaddr_r ((const char *) &in_addr,
143 sizeof (struct in_addr),
144 AF_INET, &th,
145 tmpbuf.data, tmpbuf.length,
146 &h, &herror))
148 if (herror == NETDB_INTERNAL && errno == ERANGE)
150 if (!scratch_buffer_grow (&tmpbuf))
151 goto done;
153 else
154 break;
157 if (h && (c = strchr (h->h_name, '.')))
158 domain = __strdup (++c);
162 done:
163 scratch_buffer_free (&tmpbuf);
166 __libc_lock_unlock (lock);
169 return domain;
174 getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
175 socklen_t hostlen, char *serv, socklen_t servlen,
176 int flags)
178 int serrno = errno;
179 int herrno;
180 struct hostent th;
181 int ok = 0;
182 struct scratch_buffer tmpbuf;
184 scratch_buffer_init (&tmpbuf);
186 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
187 #ifdef HAVE_LIBIDN
188 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
189 #endif
191 return EAI_BADFLAGS;
193 if (sa == NULL || addrlen < sizeof (sa_family_t))
194 return EAI_FAMILY;
196 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
197 return EAI_NONAME;
199 switch (sa->sa_family)
201 case AF_LOCAL:
202 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
203 return EAI_FAMILY;
204 break;
205 case AF_INET:
206 if (addrlen < sizeof (struct sockaddr_in))
207 return EAI_FAMILY;
208 break;
209 case AF_INET6:
210 if (addrlen < sizeof (struct sockaddr_in6))
211 return EAI_FAMILY;
212 break;
213 default:
214 return EAI_FAMILY;
217 if (host != NULL && hostlen > 0)
218 switch (sa->sa_family)
220 case AF_INET:
221 case AF_INET6:
222 if (!(flags & NI_NUMERICHOST))
224 struct hostent *h = NULL;
225 if (sa->sa_family == AF_INET6)
227 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
228 sizeof(struct in6_addr),
229 AF_INET6, &th,
230 tmpbuf.data, tmpbuf.length,
231 &h, &herrno))
232 if (herrno == NETDB_INTERNAL && errno == ERANGE)
234 if (!scratch_buffer_grow (&tmpbuf))
236 __set_h_errno (herrno);
237 return EAI_MEMORY;
240 else
241 break;
243 else
245 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
246 sizeof(struct in_addr),
247 AF_INET, &th,
248 tmpbuf.data, tmpbuf.length,
249 &h, &herrno))
250 if (herrno == NETDB_INTERNAL && errno == ERANGE)
252 if (!scratch_buffer_grow (&tmpbuf))
254 __set_h_errno (herrno);
255 return EAI_MEMORY;
258 else
259 break;
262 if (h == NULL)
264 if (herrno == NETDB_INTERNAL)
266 __set_h_errno (herrno);
267 return EAI_SYSTEM;
269 if (herrno == TRY_AGAIN)
271 __set_h_errno (herrno);
272 return EAI_AGAIN;
276 if (h)
278 char *c;
279 if ((flags & NI_NOFQDN)
280 && (c = nrl_domainname ())
281 && (c = strstr (h->h_name, c))
282 && (c != h->h_name) && (*(--c) == '.'))
283 /* Terminate the string after the prefix. */
284 *c = '\0';
286 #ifdef HAVE_LIBIDN
287 /* If requested, convert from the IDN format. */
288 if (flags & NI_IDN)
290 int idn_flags = 0;
291 if (flags & NI_IDN_ALLOW_UNASSIGNED)
292 idn_flags |= IDNA_ALLOW_UNASSIGNED;
293 if (flags & NI_IDN_USE_STD3_ASCII_RULES)
294 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
296 char *out;
297 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
298 idn_flags);
299 if (rc != IDNA_SUCCESS)
301 if (rc == IDNA_MALLOC_ERROR)
302 return EAI_MEMORY;
303 if (rc == IDNA_DLOPEN_ERROR)
304 return EAI_SYSTEM;
305 return EAI_IDN_ENCODE;
308 if (out != h->h_name)
310 h->h_name = strdupa (out);
311 free (out);
314 #endif
316 size_t len = strlen (h->h_name) + 1;
317 if (len > hostlen)
318 return EAI_OVERFLOW;
320 memcpy (host, h->h_name, len);
322 ok = 1;
326 if (!ok)
328 if (flags & NI_NAMEREQD)
330 __set_errno (serrno);
331 return EAI_NONAME;
333 else
335 const char *c;
336 if (sa->sa_family == AF_INET6)
338 const struct sockaddr_in6 *sin6p;
339 uint32_t scopeid;
341 sin6p = (const struct sockaddr_in6 *) sa;
343 c = inet_ntop (AF_INET6,
344 (const void *) &sin6p->sin6_addr, host, hostlen);
345 scopeid = sin6p->sin6_scope_id;
346 if (scopeid != 0)
348 /* Buffer is >= IFNAMSIZ+1. */
349 char scopebuf[IFNAMSIZ + 1];
350 char *scopeptr;
351 int ni_numericscope = 0;
352 size_t real_hostlen = __strnlen (host, hostlen);
353 size_t scopelen = 0;
355 scopebuf[0] = SCOPE_DELIMITER;
356 scopebuf[1] = '\0';
357 scopeptr = &scopebuf[1];
359 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
360 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
362 if (if_indextoname (scopeid, scopeptr) == NULL)
363 ++ni_numericscope;
364 else
365 scopelen = strlen (scopebuf);
367 else
368 ++ni_numericscope;
370 if (ni_numericscope)
371 scopelen = 1 + __snprintf (scopeptr,
372 (scopebuf
373 + sizeof scopebuf
374 - scopeptr),
375 "%u", scopeid);
377 if (real_hostlen + scopelen + 1 > hostlen)
378 /* Signal the buffer is too small. This is
379 what inet_ntop does. */
380 c = NULL;
381 else
382 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
385 else
386 c = inet_ntop (AF_INET,
387 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
388 host, hostlen);
389 if (c == NULL)
390 return EAI_OVERFLOW;
392 ok = 1;
394 break;
396 case AF_LOCAL:
397 if (!(flags & NI_NUMERICHOST))
399 struct utsname utsname;
401 if (!uname (&utsname))
403 strncpy (host, utsname.nodename, hostlen);
404 break;
408 if (flags & NI_NAMEREQD)
410 __set_errno (serrno);
411 return EAI_NONAME;
414 strncpy (host, "localhost", hostlen);
415 break;
417 default:
418 return EAI_FAMILY;
421 if (serv && (servlen > 0))
422 switch (sa->sa_family)
424 case AF_INET:
425 case AF_INET6:
426 if (!(flags & NI_NUMERICSERV))
428 struct servent *s, ts;
429 int e;
430 while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
431 ((flags & NI_DGRAM)
432 ? "udp" : "tcp"), &ts,
433 tmpbuf.data, tmpbuf.length, &s)))
435 if (e == ERANGE)
437 if (!scratch_buffer_grow (&tmpbuf))
438 return EAI_MEMORY;
440 else
441 break;
443 if (s)
445 strncpy (serv, s->s_name, servlen);
446 break;
450 if (__snprintf (serv, servlen, "%d",
451 ntohs (((const struct sockaddr_in *) sa)->sin_port))
452 + 1 > servlen)
453 return EAI_OVERFLOW;
455 break;
457 case AF_LOCAL:
458 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
459 break;
462 if (host && (hostlen > 0))
463 host[hostlen-1] = 0;
464 if (serv && (servlen > 0))
465 serv[servlen-1] = 0;
466 errno = serrno;
467 return 0;
469 libc_hidden_def (getnameinfo)