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
29 1. All terms of the all other applicable copyrights and licenses must be
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. */
64 #include <arpa/inet.h>
66 #include <netinet/in.h>
67 #include <sys/param.h>
68 #include <sys/socket.h>
69 #include <sys/types.h>
71 #include <sys/utsname.h>
72 #include <libc-lock.h>
73 #include <scratch_buffer.h>
76 # include <libidn/idna.h>
77 extern int __idna_to_unicode_lzlz (const char *input
, char **output
,
82 # define min(x,y) (((x) > (y)) ? (y) : (x))
85 libc_freeres_ptr (static char *domain
);
96 __libc_lock_define_initialized (static, lock
);
97 __libc_lock_lock (lock
);
102 struct hostent
*h
, th
;
104 struct scratch_buffer tmpbuf
;
106 scratch_buffer_init (&tmpbuf
);
109 while (__gethostbyname_r ("localhost", &th
,
110 tmpbuf
.data
, tmpbuf
.length
,
113 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
115 if (!scratch_buffer_grow (&tmpbuf
))
122 if (h
&& (c
= strchr (h
->h_name
, '.')))
123 domain
= __strdup (++c
);
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
))
132 if ((c
= strchr (tmpbuf
.data
, '.')))
133 domain
= __strdup (++c
);
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
,
143 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
145 if (!scratch_buffer_grow (&tmpbuf
))
152 if (h
&& (c
= strchr(h
->h_name
, '.')))
153 domain
= __strdup (++c
);
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
),
163 tmpbuf
.data
, tmpbuf
.length
,
166 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
168 if (!scratch_buffer_grow (&tmpbuf
))
175 if (h
&& (c
= strchr (h
->h_name
, '.')))
176 domain
= __strdup (++c
);
181 scratch_buffer_free (&tmpbuf
);
184 __libc_lock_unlock (lock
);
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
194 checked_copy (char *dest
, size_t destlen
, const char *source
)
196 size_t source_length
= strlen (source
);
197 if (source_length
+ 1 > destlen
)
199 memcpy (dest
, source
, source_length
+ 1);
203 /* Helper function for CHECKED_SNPRINTF below. */
205 check_sprintf_result (int result
, size_t destlen
)
209 if ((size_t) result
>= destlen
)
210 /* If ret == destlen, there was no room for the terminating NUL
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
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. */
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
)
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
,
238 if (herrno
== NETDB_INTERNAL
&& errno
== ERANGE
)
240 if (!scratch_buffer_grow (tmpbuf
))
242 __set_h_errno (herrno
);
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
,
255 if (herrno
== NETDB_INTERNAL
&& errno
== ERANGE
)
257 if (!scratch_buffer_grow (tmpbuf
))
259 __set_h_errno (herrno
);
269 if (herrno
== NETDB_INTERNAL
)
271 __set_h_errno (herrno
);
274 if (herrno
== TRY_AGAIN
)
276 __set_h_errno (herrno
);
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. */
292 /* If requested, convert from the IDN format. */
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
;
302 int rc
= __idna_to_unicode_lzlz (h
->h_name
, &out
,
304 if (rc
!= IDNA_SUCCESS
)
306 if (rc
== IDNA_MALLOC_ERROR
)
308 if (rc
== IDNA_DLOPEN_ERROR
)
310 return EAI_IDN_ENCODE
;
313 if (out
!= h
->h_name
)
315 h
->h_name
= strdupa (out
);
321 size_t len
= strlen (h
->h_name
) + 1;
325 memcpy (host
, h
->h_name
, len
);
333 /* Convert host name, AF_INET/AF_INET6 case, numeric conversion. */
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
)
345 uint32_t scopeid
= sin6p
->sin6_scope_id
;
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
);
368 const struct sockaddr_in
*sinp
= (const struct sockaddr_in
*) sa
;
369 if (inet_ntop (AF_INET
, &sinp
->sin_addr
, host
, hostlen
) == NULL
)
375 /* Convert AF_INET or AF_INET6 socket address, host part. */
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
)
389 if (flags
& NI_NAMEREQD
)
392 return gni_host_inet_numeric
393 (tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
396 /* Convert AF_LOCAL socket address, host part. */
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
)
412 return checked_copy (host
, hostlen
, "localhost");
415 /* Convert the host part of an AF_LOCAK socket address. */
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
)
425 return gni_host_inet (tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
428 return gni_host_local (tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
435 /* Convert service to string, AF_INET and AF_INET6 variant. */
437 gni_serv_inet (struct scratch_buffer
*tmpbuf
,
438 const struct sockaddr
*sa
, socklen_t addrlen
,
439 char *serv
, socklen_t servlen
, int flags
)
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
;
452 while ((e
= __getservbyport_r (sinp
->sin_port
,
454 ? "udp" : "tcp"), &ts
,
455 tmpbuf
->data
, tmpbuf
->length
, &s
)))
459 if (!scratch_buffer_grow (tmpbuf
))
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. */
474 gni_serv_local (struct scratch_buffer
*tmpbuf
,
475 const struct sockaddr
*sa
, socklen_t addrlen
,
476 char *serv
, socklen_t servlen
, int flags
)
479 (serv
, servlen
, ((const struct sockaddr_un
*) sa
)->sun_path
);
482 /* Convert service to string, dispatching to the implementations
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
)
493 return gni_serv_inet (tmpbuf
, sa
, addrlen
, serv
, servlen
, flags
);
495 return gni_serv_local (tmpbuf
, sa
, addrlen
, serv
, servlen
, flags
);
502 getnameinfo (const struct sockaddr
*sa
, socklen_t addrlen
, char *host
,
503 socklen_t hostlen
, char *serv
, socklen_t servlen
,
506 if (flags
& ~(NI_NUMERICHOST
|NI_NUMERICSERV
|NI_NOFQDN
|NI_NAMEREQD
|NI_DGRAM
508 |NI_IDN
|NI_IDN_ALLOW_UNASSIGNED
|NI_IDN_USE_STD3_ASCII_RULES
513 if (sa
== NULL
|| addrlen
< sizeof (sa_family_t
))
516 if ((flags
& NI_NAMEREQD
) && host
== NULL
&& serv
== NULL
)
519 switch (sa
->sa_family
)
522 if (addrlen
< (socklen_t
) offsetof (struct sockaddr_un
, sun_path
))
526 if (addrlen
< sizeof (struct sockaddr_in
))
530 if (addrlen
< sizeof (struct sockaddr_in6
))
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
);
545 scratch_buffer_free (&tmpbuf
);
550 if (serv
&& (servlen
> 0))
552 int result
= gni_serv (&tmpbuf
, sa
, addrlen
, serv
, servlen
, flags
);
555 scratch_buffer_free (&tmpbuf
);
560 scratch_buffer_free (&tmpbuf
);
563 libc_hidden_def (getnameinfo
)