elf.h: Add declarations for BPF
[glibc.git] / inet / getnameinfo.c
blob283da5595de1f620b8a3caf7f01f1584dc088655
1 /* Convert socket address to string using Name Service Switch modules.
2 Copyright (C) 1997-2016 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 /* The Inner Net License, Version 2.00
21 The author(s) grant permission for redistribution and use in source and
22 binary forms, with or without modification, of the software and documentation
23 provided that the following conditions are met:
25 0. If you receive a version of the software that is specifically labelled
26 as not being for redistribution (check the version message and/or README),
27 you are not permitted to redistribute that version of the software in any
28 way or form.
29 1. All terms of the all other applicable copyrights and licenses must be
30 followed.
31 2. Redistributions of source code must retain the authors' copyright
32 notice(s), this list of conditions, and the following disclaimer.
33 3. Redistributions in binary form must reproduce the authors' copyright
34 notice(s), this list of conditions, and the following disclaimer in the
35 documentation and/or other materials provided with the distribution.
36 4. [The copyright holder has authorized the removal of this clause.]
37 5. Neither the name(s) of the author(s) nor the names of its contributors
38 may be used to endorse or promote products derived from this software
39 without specific prior written permission.
41 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
42 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
43 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
45 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
48 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 If these license terms cause you a real problem, contact the author. */
54 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
56 #include <errno.h>
57 #include <netdb.h>
58 #include <stddef.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <stdint.h>
64 #include <arpa/inet.h>
65 #include <net/if.h>
66 #include <netinet/in.h>
67 #include <sys/param.h>
68 #include <sys/socket.h>
69 #include <sys/types.h>
70 #include <sys/un.h>
71 #include <sys/utsname.h>
72 #include <libc-lock.h>
73 #include <scratch_buffer.h>
75 #ifdef HAVE_LIBIDN
76 # include <libidn/idna.h>
77 extern int __idna_to_unicode_lzlz (const char *input, char **output,
78 int flags);
79 #endif
81 #ifndef min
82 # define min(x,y) (((x) > (y)) ? (y) : (x))
83 #endif /* min */
85 libc_freeres_ptr (static char *domain);
88 static char *
89 internal_function
90 nrl_domainname (void)
92 static int not_first;
94 if (! not_first)
96 __libc_lock_define_initialized (static, lock);
97 __libc_lock_lock (lock);
99 if (! not_first)
101 char *c;
102 struct hostent *h, th;
103 int herror;
104 struct scratch_buffer tmpbuf;
106 scratch_buffer_init (&tmpbuf);
107 not_first = 1;
109 while (__gethostbyname_r ("localhost", &th,
110 tmpbuf.data, tmpbuf.length,
111 &h, &herror))
113 if (herror == NETDB_INTERNAL && errno == ERANGE)
115 if (!scratch_buffer_grow (&tmpbuf))
116 goto done;
118 else
119 break;
122 if (h && (c = strchr (h->h_name, '.')))
123 domain = __strdup (++c);
124 else
126 /* The name contains no domain information. Use the name
127 now to get more information. */
128 while (__gethostname (tmpbuf.data, tmpbuf.length))
129 if (!scratch_buffer_grow (&tmpbuf))
130 goto done;
132 if ((c = strchr (tmpbuf.data, '.')))
133 domain = __strdup (++c);
134 else
136 /* We need to preserve the hostname. */
137 const char *hstname = strdupa (tmpbuf.data);
139 while (__gethostbyname_r (hstname, &th,
140 tmpbuf.data, tmpbuf.length,
141 &h, &herror))
143 if (herror == NETDB_INTERNAL && errno == ERANGE)
145 if (!scratch_buffer_grow (&tmpbuf))
146 goto done;
148 else
149 break;
152 if (h && (c = strchr(h->h_name, '.')))
153 domain = __strdup (++c);
154 else
156 struct in_addr in_addr;
158 in_addr.s_addr = htonl (INADDR_LOOPBACK);
160 while (__gethostbyaddr_r ((const char *) &in_addr,
161 sizeof (struct in_addr),
162 AF_INET, &th,
163 tmpbuf.data, tmpbuf.length,
164 &h, &herror))
166 if (herror == NETDB_INTERNAL && errno == ERANGE)
168 if (!scratch_buffer_grow (&tmpbuf))
169 goto done;
171 else
172 break;
175 if (h && (c = strchr (h->h_name, '.')))
176 domain = __strdup (++c);
180 done:
181 scratch_buffer_free (&tmpbuf);
184 __libc_lock_unlock (lock);
187 return domain;
190 /* Copy a string to a destination buffer with length checking. Return
191 EAI_OVERFLOW if the buffer is not large enough, and 0 on
192 success. */
193 static int
194 checked_copy (char *dest, size_t destlen, const char *source)
196 size_t source_length = strlen (source);
197 if (source_length + 1 > destlen)
198 return EAI_OVERFLOW;
199 memcpy (dest, source, source_length + 1);
200 return 0;
203 /* Helper function for CHECKED_SNPRINTF below. */
204 static int
205 check_sprintf_result (int result, size_t destlen)
207 if (result < 0)
208 return EAI_SYSTEM;
209 if ((size_t) result >= destlen)
210 /* If ret == destlen, there was no room for the terminating NUL
211 character. */
212 return EAI_OVERFLOW;
213 return 0;
216 /* Format a string in the destination buffer. Return 0 on success,
217 EAI_OVERFLOW in case the buffer is too small, or EAI_SYSTEM on any
218 other error. */
219 #define CHECKED_SNPRINTF(dest, destlen, format, ...) \
220 check_sprintf_result \
221 (__snprintf (dest, destlen, format, __VA_ARGS__), destlen)
223 /* Convert host name, AF_INET/AF_INET6 case, name only. */
224 static int
225 gni_host_inet_name (struct scratch_buffer *tmpbuf,
226 const struct sockaddr *sa, socklen_t addrlen,
227 char *host, socklen_t hostlen, int flags)
229 int herrno;
230 struct hostent th;
231 struct hostent *h = NULL;
232 if (sa->sa_family == AF_INET6)
234 const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
235 while (__gethostbyaddr_r (&sin6p->sin6_addr, sizeof(struct in6_addr),
236 AF_INET6, &th, tmpbuf->data, tmpbuf->length,
237 &h, &herrno))
238 if (herrno == NETDB_INTERNAL && errno == ERANGE)
240 if (!scratch_buffer_grow (tmpbuf))
242 __set_h_errno (herrno);
243 return EAI_MEMORY;
246 else
247 break;
249 else
251 const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
252 while (__gethostbyaddr_r (&sinp->sin_addr, sizeof(struct in_addr),
253 AF_INET, &th, tmpbuf->data, tmpbuf->length,
254 &h, &herrno))
255 if (herrno == NETDB_INTERNAL && errno == ERANGE)
257 if (!scratch_buffer_grow (tmpbuf))
259 __set_h_errno (herrno);
260 return EAI_MEMORY;
263 else
264 break;
267 if (h == NULL)
269 if (herrno == NETDB_INTERNAL)
271 __set_h_errno (herrno);
272 return EAI_SYSTEM;
274 if (herrno == TRY_AGAIN)
276 __set_h_errno (herrno);
277 return EAI_AGAIN;
281 if (h)
283 char *c;
284 if ((flags & NI_NOFQDN)
285 && (c = nrl_domainname ())
286 && (c = strstr (h->h_name, c))
287 && (c != h->h_name) && (*(--c) == '.'))
288 /* Terminate the string after the prefix. */
289 *c = '\0';
291 #ifdef HAVE_LIBIDN
292 /* If requested, convert from the IDN format. */
293 if (flags & NI_IDN)
295 int idn_flags = 0;
296 if (flags & NI_IDN_ALLOW_UNASSIGNED)
297 idn_flags |= IDNA_ALLOW_UNASSIGNED;
298 if (flags & NI_IDN_USE_STD3_ASCII_RULES)
299 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
301 char *out;
302 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
303 idn_flags);
304 if (rc != IDNA_SUCCESS)
306 if (rc == IDNA_MALLOC_ERROR)
307 return EAI_MEMORY;
308 if (rc == IDNA_DLOPEN_ERROR)
309 return EAI_SYSTEM;
310 return EAI_IDN_ENCODE;
313 if (out != h->h_name)
315 h->h_name = strdupa (out);
316 free (out);
319 #endif
321 size_t len = strlen (h->h_name) + 1;
322 if (len > hostlen)
323 return EAI_OVERFLOW;
325 memcpy (host, h->h_name, len);
327 return 0;
330 return EAI_NONAME;
333 /* Convert host name, AF_INET/AF_INET6 case, numeric conversion. */
334 static int
335 gni_host_inet_numeric (struct scratch_buffer *tmpbuf,
336 const struct sockaddr *sa, socklen_t addrlen,
337 char *host, socklen_t hostlen, int flags)
339 if (sa->sa_family == AF_INET6)
341 const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
342 if (inet_ntop (AF_INET6, &sin6p->sin6_addr, host, hostlen) == NULL)
343 return EAI_OVERFLOW;
345 uint32_t scopeid = sin6p->sin6_scope_id;
346 if (scopeid != 0)
348 size_t used_hostlen = __strnlen (host, hostlen);
349 /* Location of the scope string in the host buffer. */
350 char *scope_start = host + used_hostlen;
351 size_t scope_length = hostlen - used_hostlen;
353 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
354 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
356 char scopebuf[IFNAMSIZ];
357 if (if_indextoname (scopeid, scopebuf) != NULL)
358 return CHECKED_SNPRINTF
359 (scope_start, scope_length,
360 "%c%s", SCOPE_DELIMITER, scopebuf);
362 return CHECKED_SNPRINTF
363 (scope_start, scope_length, "%c%u", SCOPE_DELIMITER, scopeid);
366 else
368 const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
369 if (inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen) == NULL)
370 return EAI_OVERFLOW;
372 return 0;
375 /* Convert AF_INET or AF_INET6 socket address, host part. */
376 static int
377 gni_host_inet (struct scratch_buffer *tmpbuf,
378 const struct sockaddr *sa, socklen_t addrlen,
379 char *host, socklen_t hostlen, int flags)
381 if (!(flags & NI_NUMERICHOST))
383 int result = gni_host_inet_name
384 (tmpbuf, sa, addrlen, host, hostlen, flags);
385 if (result != EAI_NONAME)
386 return result;
389 if (flags & NI_NAMEREQD)
390 return EAI_NONAME;
391 else
392 return gni_host_inet_numeric
393 (tmpbuf, sa, addrlen, host, hostlen, flags);
396 /* Convert AF_LOCAL socket address, host part. */
397 static int
398 gni_host_local (struct scratch_buffer *tmpbuf,
399 const struct sockaddr *sa, socklen_t addrlen,
400 char *host, socklen_t hostlen, int flags)
402 if (!(flags & NI_NUMERICHOST))
404 struct utsname utsname;
405 if (uname (&utsname) == 0)
406 return checked_copy (host, hostlen, utsname.nodename);
409 if (flags & NI_NAMEREQD)
410 return EAI_NONAME;
412 return checked_copy (host, hostlen, "localhost");
415 /* Convert the host part of an AF_LOCAK socket address. */
416 static int
417 gni_host (struct scratch_buffer *tmpbuf,
418 const struct sockaddr *sa, socklen_t addrlen,
419 char *host, socklen_t hostlen, int flags)
421 switch (sa->sa_family)
423 case AF_INET:
424 case AF_INET6:
425 return gni_host_inet (tmpbuf, sa, addrlen, host, hostlen, flags);
427 case AF_LOCAL:
428 return gni_host_local (tmpbuf, sa, addrlen, host, hostlen, flags);
430 default:
431 return EAI_FAMILY;
435 /* Convert service to string, AF_INET and AF_INET6 variant. */
436 static int
437 gni_serv_inet (struct scratch_buffer *tmpbuf,
438 const struct sockaddr *sa, socklen_t addrlen,
439 char *serv, socklen_t servlen, int flags)
441 _Static_assert
442 (offsetof (struct sockaddr_in, sin_port)
443 == offsetof (struct sockaddr_in6, sin6_port)
444 && sizeof (((struct sockaddr_in) {}).sin_port) == sizeof (in_port_t)
445 && sizeof (((struct sockaddr_in6) {}).sin6_port) == sizeof (in_port_t),
446 "AF_INET and AF_INET6 port consistency");
447 const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
448 if (!(flags & NI_NUMERICSERV))
450 struct servent *s, ts;
451 int e;
452 while ((e = __getservbyport_r (sinp->sin_port,
453 ((flags & NI_DGRAM)
454 ? "udp" : "tcp"), &ts,
455 tmpbuf->data, tmpbuf->length, &s)))
457 if (e == ERANGE)
459 if (!scratch_buffer_grow (tmpbuf))
460 return EAI_MEMORY;
462 else
463 break;
465 if (s)
466 return checked_copy (serv, servlen, s->s_name);
467 /* Fall through to numeric conversion. */
469 return CHECKED_SNPRINTF (serv, servlen, "%d", ntohs (sinp->sin_port));
472 /* Convert service to string, AF_LOCAL variant. */
473 static int
474 gni_serv_local (struct scratch_buffer *tmpbuf,
475 const struct sockaddr *sa, socklen_t addrlen,
476 char *serv, socklen_t servlen, int flags)
478 return checked_copy
479 (serv, servlen, ((const struct sockaddr_un *) sa)->sun_path);
482 /* Convert service to string, dispatching to the implementations
483 above. */
484 static int
485 gni_serv (struct scratch_buffer *tmpbuf,
486 const struct sockaddr *sa, socklen_t addrlen,
487 char *serv, socklen_t servlen, int flags)
489 switch (sa->sa_family)
491 case AF_INET:
492 case AF_INET6:
493 return gni_serv_inet (tmpbuf, sa, addrlen, serv, servlen, flags);
494 case AF_LOCAL:
495 return gni_serv_local (tmpbuf, sa, addrlen, serv, servlen, flags);
496 default:
497 return EAI_FAMILY;
502 getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
503 socklen_t hostlen, char *serv, socklen_t servlen,
504 int flags)
506 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
507 #ifdef HAVE_LIBIDN
508 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
509 #endif
511 return EAI_BADFLAGS;
513 if (sa == NULL || addrlen < sizeof (sa_family_t))
514 return EAI_FAMILY;
516 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
517 return EAI_NONAME;
519 switch (sa->sa_family)
521 case AF_LOCAL:
522 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
523 return EAI_FAMILY;
524 break;
525 case AF_INET:
526 if (addrlen < sizeof (struct sockaddr_in))
527 return EAI_FAMILY;
528 break;
529 case AF_INET6:
530 if (addrlen < sizeof (struct sockaddr_in6))
531 return EAI_FAMILY;
532 break;
533 default:
534 return EAI_FAMILY;
537 struct scratch_buffer tmpbuf;
538 scratch_buffer_init (&tmpbuf);
540 if (host != NULL && hostlen > 0)
542 int result = gni_host (&tmpbuf, sa, addrlen, host, hostlen, flags);
543 if (result != 0)
545 scratch_buffer_free (&tmpbuf);
546 return result;
550 if (serv && (servlen > 0))
552 int result = gni_serv (&tmpbuf, sa, addrlen, serv, servlen, flags);
553 if (result != 0)
555 scratch_buffer_free (&tmpbuf);
556 return result;
560 scratch_buffer_free (&tmpbuf);
561 return 0;
563 libc_hidden_def (getnameinfo)