ILP32 math changes
[glibc.git] / inet / getnameinfo.c
blobb41e555f3cec99be9c2a5285911e03e1d44700bd
1 /* Convert socket address to string using Name Service Switch modules.
2 Copyright (C) 1997-2017 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 nrl_domainname (void)
91 static int not_first;
93 if (! not_first)
95 __libc_lock_define_initialized (static, lock);
96 __libc_lock_lock (lock);
98 if (! not_first)
100 char *c;
101 struct hostent *h, th;
102 int herror;
103 struct scratch_buffer tmpbuf;
105 scratch_buffer_init (&tmpbuf);
106 not_first = 1;
108 while (__gethostbyname_r ("localhost", &th,
109 tmpbuf.data, tmpbuf.length,
110 &h, &herror))
112 if (herror == NETDB_INTERNAL && errno == ERANGE)
114 if (!scratch_buffer_grow (&tmpbuf))
115 goto done;
117 else
118 break;
121 if (h && (c = strchr (h->h_name, '.')))
122 domain = __strdup (++c);
123 else
125 /* The name contains no domain information. Use the name
126 now to get more information. */
127 while (__gethostname (tmpbuf.data, tmpbuf.length))
128 if (!scratch_buffer_grow (&tmpbuf))
129 goto done;
131 if ((c = strchr (tmpbuf.data, '.')))
132 domain = __strdup (++c);
133 else
135 /* We need to preserve the hostname. */
136 const char *hstname = strdupa (tmpbuf.data);
138 while (__gethostbyname_r (hstname, &th,
139 tmpbuf.data, tmpbuf.length,
140 &h, &herror))
142 if (herror == NETDB_INTERNAL && errno == ERANGE)
144 if (!scratch_buffer_grow (&tmpbuf))
145 goto done;
147 else
148 break;
151 if (h && (c = strchr(h->h_name, '.')))
152 domain = __strdup (++c);
153 else
155 struct in_addr in_addr;
157 in_addr.s_addr = htonl (INADDR_LOOPBACK);
159 while (__gethostbyaddr_r ((const char *) &in_addr,
160 sizeof (struct in_addr),
161 AF_INET, &th,
162 tmpbuf.data, tmpbuf.length,
163 &h, &herror))
165 if (herror == NETDB_INTERNAL && errno == ERANGE)
167 if (!scratch_buffer_grow (&tmpbuf))
168 goto done;
170 else
171 break;
174 if (h && (c = strchr (h->h_name, '.')))
175 domain = __strdup (++c);
179 done:
180 scratch_buffer_free (&tmpbuf);
183 __libc_lock_unlock (lock);
186 return domain;
189 /* Copy a string to a destination buffer with length checking. Return
190 EAI_OVERFLOW if the buffer is not large enough, and 0 on
191 success. */
192 static int
193 checked_copy (char *dest, size_t destlen, const char *source)
195 size_t source_length = strlen (source);
196 if (source_length + 1 > destlen)
197 return EAI_OVERFLOW;
198 memcpy (dest, source, source_length + 1);
199 return 0;
202 /* Helper function for CHECKED_SNPRINTF below. */
203 static int
204 check_sprintf_result (int result, size_t destlen)
206 if (result < 0)
207 return EAI_SYSTEM;
208 if ((size_t) result >= destlen)
209 /* If ret == destlen, there was no room for the terminating NUL
210 character. */
211 return EAI_OVERFLOW;
212 return 0;
215 /* Format a string in the destination buffer. Return 0 on success,
216 EAI_OVERFLOW in case the buffer is too small, or EAI_SYSTEM on any
217 other error. */
218 #define CHECKED_SNPRINTF(dest, destlen, format, ...) \
219 check_sprintf_result \
220 (__snprintf (dest, destlen, format, __VA_ARGS__), destlen)
222 /* Convert host name, AF_INET/AF_INET6 case, name only. */
223 static int
224 gni_host_inet_name (struct scratch_buffer *tmpbuf,
225 const struct sockaddr *sa, socklen_t addrlen,
226 char *host, socklen_t hostlen, int flags)
228 int herrno;
229 struct hostent th;
230 struct hostent *h = NULL;
231 if (sa->sa_family == AF_INET6)
233 const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
234 while (__gethostbyaddr_r (&sin6p->sin6_addr, sizeof(struct in6_addr),
235 AF_INET6, &th, tmpbuf->data, tmpbuf->length,
236 &h, &herrno))
237 if (herrno == NETDB_INTERNAL && errno == ERANGE)
239 if (!scratch_buffer_grow (tmpbuf))
241 __set_h_errno (herrno);
242 return EAI_MEMORY;
245 else
246 break;
248 else
250 const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
251 while (__gethostbyaddr_r (&sinp->sin_addr, sizeof(struct in_addr),
252 AF_INET, &th, tmpbuf->data, tmpbuf->length,
253 &h, &herrno))
254 if (herrno == NETDB_INTERNAL && errno == ERANGE)
256 if (!scratch_buffer_grow (tmpbuf))
258 __set_h_errno (herrno);
259 return EAI_MEMORY;
262 else
263 break;
266 if (h == NULL)
268 if (herrno == NETDB_INTERNAL)
270 __set_h_errno (herrno);
271 return EAI_SYSTEM;
273 if (herrno == TRY_AGAIN)
275 __set_h_errno (herrno);
276 return EAI_AGAIN;
280 if (h)
282 char *c;
283 if ((flags & NI_NOFQDN)
284 && (c = nrl_domainname ())
285 && (c = strstr (h->h_name, c))
286 && (c != h->h_name) && (*(--c) == '.'))
287 /* Terminate the string after the prefix. */
288 *c = '\0';
290 #ifdef HAVE_LIBIDN
291 /* If requested, convert from the IDN format. */
292 if (flags & NI_IDN)
294 int idn_flags = 0;
295 if (flags & NI_IDN_ALLOW_UNASSIGNED)
296 idn_flags |= IDNA_ALLOW_UNASSIGNED;
297 if (flags & NI_IDN_USE_STD3_ASCII_RULES)
298 idn_flags |= IDNA_USE_STD3_ASCII_RULES;
300 char *out;
301 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
302 idn_flags);
303 if (rc != IDNA_SUCCESS)
305 if (rc == IDNA_MALLOC_ERROR)
306 return EAI_MEMORY;
307 if (rc == IDNA_DLOPEN_ERROR)
308 return EAI_SYSTEM;
309 return EAI_IDN_ENCODE;
312 if (out != h->h_name)
314 h->h_name = strdupa (out);
315 free (out);
318 #endif
320 size_t len = strlen (h->h_name) + 1;
321 if (len > hostlen)
322 return EAI_OVERFLOW;
324 memcpy (host, h->h_name, len);
326 return 0;
329 return EAI_NONAME;
332 /* Convert host name, AF_INET/AF_INET6 case, numeric conversion. */
333 static int
334 gni_host_inet_numeric (struct scratch_buffer *tmpbuf,
335 const struct sockaddr *sa, socklen_t addrlen,
336 char *host, socklen_t hostlen, int flags)
338 if (sa->sa_family == AF_INET6)
340 const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
341 if (inet_ntop (AF_INET6, &sin6p->sin6_addr, host, hostlen) == NULL)
342 return EAI_OVERFLOW;
344 uint32_t scopeid = sin6p->sin6_scope_id;
345 if (scopeid != 0)
347 size_t used_hostlen = __strnlen (host, hostlen);
348 /* Location of the scope string in the host buffer. */
349 char *scope_start = host + used_hostlen;
350 size_t scope_length = hostlen - used_hostlen;
352 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
353 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
355 char scopebuf[IFNAMSIZ];
356 if (if_indextoname (scopeid, scopebuf) != NULL)
357 return CHECKED_SNPRINTF
358 (scope_start, scope_length,
359 "%c%s", SCOPE_DELIMITER, scopebuf);
361 return CHECKED_SNPRINTF
362 (scope_start, scope_length, "%c%u", SCOPE_DELIMITER, scopeid);
365 else
367 const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
368 if (inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen) == NULL)
369 return EAI_OVERFLOW;
371 return 0;
374 /* Convert AF_INET or AF_INET6 socket address, host part. */
375 static int
376 gni_host_inet (struct scratch_buffer *tmpbuf,
377 const struct sockaddr *sa, socklen_t addrlen,
378 char *host, socklen_t hostlen, int flags)
380 if (!(flags & NI_NUMERICHOST))
382 int result = gni_host_inet_name
383 (tmpbuf, sa, addrlen, host, hostlen, flags);
384 if (result != EAI_NONAME)
385 return result;
388 if (flags & NI_NAMEREQD)
389 return EAI_NONAME;
390 else
391 return gni_host_inet_numeric
392 (tmpbuf, sa, addrlen, host, hostlen, flags);
395 /* Convert AF_LOCAL socket address, host part. */
396 static int
397 gni_host_local (struct scratch_buffer *tmpbuf,
398 const struct sockaddr *sa, socklen_t addrlen,
399 char *host, socklen_t hostlen, int flags)
401 if (!(flags & NI_NUMERICHOST))
403 struct utsname utsname;
404 if (uname (&utsname) == 0)
405 return checked_copy (host, hostlen, utsname.nodename);
408 if (flags & NI_NAMEREQD)
409 return EAI_NONAME;
411 return checked_copy (host, hostlen, "localhost");
414 /* Convert the host part of an AF_LOCAK socket address. */
415 static int
416 gni_host (struct scratch_buffer *tmpbuf,
417 const struct sockaddr *sa, socklen_t addrlen,
418 char *host, socklen_t hostlen, int flags)
420 switch (sa->sa_family)
422 case AF_INET:
423 case AF_INET6:
424 return gni_host_inet (tmpbuf, sa, addrlen, host, hostlen, flags);
426 case AF_LOCAL:
427 return gni_host_local (tmpbuf, sa, addrlen, host, hostlen, flags);
429 default:
430 return EAI_FAMILY;
434 /* Convert service to string, AF_INET and AF_INET6 variant. */
435 static int
436 gni_serv_inet (struct scratch_buffer *tmpbuf,
437 const struct sockaddr *sa, socklen_t addrlen,
438 char *serv, socklen_t servlen, int flags)
440 _Static_assert
441 (offsetof (struct sockaddr_in, sin_port)
442 == offsetof (struct sockaddr_in6, sin6_port)
443 && sizeof (((struct sockaddr_in) {}).sin_port) == sizeof (in_port_t)
444 && sizeof (((struct sockaddr_in6) {}).sin6_port) == sizeof (in_port_t),
445 "AF_INET and AF_INET6 port consistency");
446 const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
447 if (!(flags & NI_NUMERICSERV))
449 struct servent *s, ts;
450 int e;
451 while ((e = __getservbyport_r (sinp->sin_port,
452 ((flags & NI_DGRAM)
453 ? "udp" : "tcp"), &ts,
454 tmpbuf->data, tmpbuf->length, &s)))
456 if (e == ERANGE)
458 if (!scratch_buffer_grow (tmpbuf))
459 return EAI_MEMORY;
461 else
462 break;
464 if (s)
465 return checked_copy (serv, servlen, s->s_name);
466 /* Fall through to numeric conversion. */
468 return CHECKED_SNPRINTF (serv, servlen, "%d", ntohs (sinp->sin_port));
471 /* Convert service to string, AF_LOCAL variant. */
472 static int
473 gni_serv_local (struct scratch_buffer *tmpbuf,
474 const struct sockaddr *sa, socklen_t addrlen,
475 char *serv, socklen_t servlen, int flags)
477 return checked_copy
478 (serv, servlen, ((const struct sockaddr_un *) sa)->sun_path);
481 /* Convert service to string, dispatching to the implementations
482 above. */
483 static int
484 gni_serv (struct scratch_buffer *tmpbuf,
485 const struct sockaddr *sa, socklen_t addrlen,
486 char *serv, socklen_t servlen, int flags)
488 switch (sa->sa_family)
490 case AF_INET:
491 case AF_INET6:
492 return gni_serv_inet (tmpbuf, sa, addrlen, serv, servlen, flags);
493 case AF_LOCAL:
494 return gni_serv_local (tmpbuf, sa, addrlen, serv, servlen, flags);
495 default:
496 return EAI_FAMILY;
501 getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
502 socklen_t hostlen, char *serv, socklen_t servlen,
503 int flags)
505 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
506 #ifdef HAVE_LIBIDN
507 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
508 #endif
510 return EAI_BADFLAGS;
512 if (sa == NULL || addrlen < sizeof (sa_family_t))
513 return EAI_FAMILY;
515 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
516 return EAI_NONAME;
518 switch (sa->sa_family)
520 case AF_LOCAL:
521 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
522 return EAI_FAMILY;
523 break;
524 case AF_INET:
525 if (addrlen < sizeof (struct sockaddr_in))
526 return EAI_FAMILY;
527 break;
528 case AF_INET6:
529 if (addrlen < sizeof (struct sockaddr_in6))
530 return EAI_FAMILY;
531 break;
532 default:
533 return EAI_FAMILY;
536 struct scratch_buffer tmpbuf;
537 scratch_buffer_init (&tmpbuf);
539 if (host != NULL && hostlen > 0)
541 int result = gni_host (&tmpbuf, sa, addrlen, host, hostlen, flags);
542 if (result != 0)
544 scratch_buffer_free (&tmpbuf);
545 return result;
549 if (serv && (servlen > 0))
551 int result = gni_serv (&tmpbuf, sa, addrlen, serv, servlen, flags);
552 if (result != 0)
554 scratch_buffer_free (&tmpbuf);
555 return result;
559 scratch_buffer_free (&tmpbuf);
560 return 0;
562 libc_hidden_def (getnameinfo)