1 /* Convert socket address to string using Name Service Switch modules.
2 Copyright (C) 1997-2022 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 <https://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>
74 #include <net-internal.h>
77 # define min(x,y) (((x) > (y)) ? (y) : (x))
80 libc_freeres_ptr (static char *domain
);
82 /* Former NI_IDN_ALLOW_UNASSIGNED, NI_IDN_USE_STD3_ASCII_RULES flags,
84 #define DEPRECATED_NI_IDN 192
86 /* Return true if no memory allocation failure happened (even if domain
87 name could not be obtained) or false otherwise. */
89 nrl_domainname_core (struct scratch_buffer
*tmpbuf
)
92 struct hostent
*h
, th
;
95 while (__gethostbyname_r ("localhost", &th
, tmpbuf
->data
, tmpbuf
->length
,
98 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
100 if (!scratch_buffer_grow (tmpbuf
))
107 if (h
!= NULL
&& (c
= strchr (h
->h_name
, '.')) != NULL
)
109 domain
= __strdup (++c
);
110 return domain
!= NULL
;
113 /* The name contains no domain information. Use the name
114 now to get more information. */
115 while (__gethostname (tmpbuf
->data
, tmpbuf
->length
))
116 if (!scratch_buffer_grow (tmpbuf
))
119 if ((c
= strchr (tmpbuf
->data
, '.')) != NULL
)
121 domain
= __strdup (++c
);
122 return domain
!= NULL
;
125 /* We need to preserve the hostname. */
126 size_t hstnamelen
= strlen (tmpbuf
->data
) + 1;
127 while (__gethostbyname_r (tmpbuf
->data
, &th
, tmpbuf
->data
+ hstnamelen
,
128 tmpbuf
->length
- hstnamelen
, &h
, &herror
))
130 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
132 if (!scratch_buffer_grow_preserve (tmpbuf
))
139 if (h
!= NULL
&& (c
= strchr(h
->h_name
, '.')) != NULL
)
141 domain
= __strdup (++c
);
142 return domain
!= NULL
;
145 struct in_addr in_addr
= { .s_addr
= htonl (INADDR_LOOPBACK
) };
147 while (__gethostbyaddr_r ((const char *) &in_addr
, sizeof (struct in_addr
),
148 AF_INET
, &th
, tmpbuf
->data
, tmpbuf
->length
, &h
,
151 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
153 if (!scratch_buffer_grow (tmpbuf
))
160 if (h
!= NULL
&& (c
= strchr (h
->h_name
, '.')) != NULL
)
162 domain
= __strdup (++c
);
163 return domain
!= NULL
;
169 nrl_domainname (void)
171 static int not_first
;
173 if (__glibc_likely (atomic_load_acquire (¬_first
) != 0))
178 __libc_lock_define_initialized (static, lock
);
179 __libc_lock_lock (lock
);
181 if (atomic_load_relaxed (¬_first
) == 0)
183 struct scratch_buffer tmpbuf
;
184 scratch_buffer_init (&tmpbuf
);
186 if ((r
= nrl_domainname_core (&tmpbuf
)))
187 atomic_store_release (¬_first
, 1);
189 scratch_buffer_free (&tmpbuf
);
192 __libc_lock_unlock (lock
);
197 /* Copy a string to a destination buffer with length checking. Return
198 EAI_OVERFLOW if the buffer is not large enough, and 0 on
201 checked_copy (char *dest
, size_t destlen
, const char *source
)
203 size_t source_length
= strlen (source
);
204 if (source_length
+ 1 > destlen
)
206 memcpy (dest
, source
, source_length
+ 1);
210 /* Helper function for CHECKED_SNPRINTF below. */
212 check_sprintf_result (int result
, size_t destlen
)
216 if ((size_t) result
>= destlen
)
217 /* If ret == destlen, there was no room for the terminating NUL
223 /* Format a string in the destination buffer. Return 0 on success,
224 EAI_OVERFLOW in case the buffer is too small, or EAI_SYSTEM on any
226 #define CHECKED_SNPRINTF(dest, destlen, format, ...) \
227 check_sprintf_result \
228 (__snprintf (dest, destlen, format, __VA_ARGS__), destlen)
230 /* Convert host name, AF_INET/AF_INET6 case, name only. */
232 gni_host_inet_name (struct scratch_buffer
*tmpbuf
,
233 const struct sockaddr
*sa
, socklen_t addrlen
,
234 char *host
, socklen_t hostlen
, int flags
)
238 struct hostent
*h
= NULL
;
239 if (sa
->sa_family
== AF_INET6
)
241 const struct sockaddr_in6
*sin6p
= (const struct sockaddr_in6
*) sa
;
242 while (__gethostbyaddr_r (&sin6p
->sin6_addr
, sizeof(struct in6_addr
),
243 AF_INET6
, &th
, tmpbuf
->data
, tmpbuf
->length
,
245 if (herrno
== NETDB_INTERNAL
&& errno
== ERANGE
)
247 if (!scratch_buffer_grow (tmpbuf
))
249 __set_h_errno (herrno
);
258 const struct sockaddr_in
*sinp
= (const struct sockaddr_in
*) sa
;
259 while (__gethostbyaddr_r (&sinp
->sin_addr
, sizeof(struct in_addr
),
260 AF_INET
, &th
, tmpbuf
->data
, tmpbuf
->length
,
262 if (herrno
== NETDB_INTERNAL
&& errno
== ERANGE
)
264 if (!scratch_buffer_grow (tmpbuf
))
266 __set_h_errno (herrno
);
276 if (herrno
== NETDB_INTERNAL
)
278 __set_h_errno (herrno
);
281 if (herrno
== TRY_AGAIN
)
283 __set_h_errno (herrno
);
290 if (flags
& NI_NOFQDN
)
292 if (!nrl_domainname ())
296 if (c
!= NULL
&& (c
= strstr (h
->h_name
, c
))
297 && (c
!= h
->h_name
) && (*(--c
) == '.'))
298 /* Terminate the string after the prefix. */
302 /* If requested, convert from the IDN format. */
303 bool do_idn
= flags
& NI_IDN
;
307 int rc
= __idna_from_dns_encoding (h
->h_name
, &h_name
);
308 if (rc
== EAI_IDN_ENCODE
)
309 /* Use the punycode name as a fallback. */
317 size_t len
= strlen (h_name
) + 1;
320 memcpy (host
, h_name
, len
);
331 /* Convert host name, AF_INET/AF_INET6 case, numeric conversion. */
333 gni_host_inet_numeric (struct scratch_buffer
*tmpbuf
,
334 const struct sockaddr
*sa
, socklen_t addrlen
,
335 char *host
, socklen_t hostlen
, int flags
)
337 if (sa
->sa_family
== AF_INET6
)
339 const struct sockaddr_in6
*sin6p
= (const struct sockaddr_in6
*) sa
;
340 if (inet_ntop (AF_INET6
, &sin6p
->sin6_addr
, host
, hostlen
) == NULL
)
343 uint32_t scopeid
= sin6p
->sin6_scope_id
;
346 size_t used_hostlen
= __strnlen (host
, hostlen
);
347 /* Location of the scope string in the host buffer. */
348 char *scope_start
= host
+ used_hostlen
;
349 size_t scope_length
= hostlen
- used_hostlen
;
351 if (IN6_IS_ADDR_LINKLOCAL (&sin6p
->sin6_addr
)
352 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p
->sin6_addr
))
354 char scopebuf
[IFNAMSIZ
];
355 if (if_indextoname (scopeid
, scopebuf
) != NULL
)
356 return CHECKED_SNPRINTF
357 (scope_start
, scope_length
,
358 "%c%s", SCOPE_DELIMITER
, scopebuf
);
360 return CHECKED_SNPRINTF
361 (scope_start
, scope_length
, "%c%u", SCOPE_DELIMITER
, scopeid
);
366 const struct sockaddr_in
*sinp
= (const struct sockaddr_in
*) sa
;
367 if (inet_ntop (AF_INET
, &sinp
->sin_addr
, host
, hostlen
) == NULL
)
373 /* Convert AF_INET or AF_INET6 socket address, host part. */
375 gni_host_inet (struct scratch_buffer
*tmpbuf
,
376 const struct sockaddr
*sa
, socklen_t addrlen
,
377 char *host
, socklen_t hostlen
, int flags
)
379 if (!(flags
& NI_NUMERICHOST
))
381 int result
= gni_host_inet_name
382 (tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
383 if (result
!= EAI_NONAME
)
387 if (flags
& NI_NAMEREQD
)
390 return gni_host_inet_numeric
391 (tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
394 /* Convert AF_LOCAL socket address, host part. */
396 gni_host_local (struct scratch_buffer
*tmpbuf
,
397 const struct sockaddr
*sa
, socklen_t addrlen
,
398 char *host
, socklen_t hostlen
, int flags
)
400 if (!(flags
& NI_NUMERICHOST
))
402 struct utsname utsname
;
403 if (uname (&utsname
) == 0)
404 return checked_copy (host
, hostlen
, utsname
.nodename
);
407 if (flags
& NI_NAMEREQD
)
410 return checked_copy (host
, hostlen
, "localhost");
413 /* Convert the host part of an AF_LOCAK socket address. */
415 gni_host (struct scratch_buffer
*tmpbuf
,
416 const struct sockaddr
*sa
, socklen_t addrlen
,
417 char *host
, socklen_t hostlen
, int flags
)
419 switch (sa
->sa_family
)
423 return gni_host_inet (tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
426 return gni_host_local (tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
433 /* Convert service to string, AF_INET and AF_INET6 variant. */
435 gni_serv_inet (struct scratch_buffer
*tmpbuf
,
436 const struct sockaddr
*sa
, socklen_t addrlen
,
437 char *serv
, socklen_t servlen
, int flags
)
440 (offsetof (struct sockaddr_in
, sin_port
)
441 == offsetof (struct sockaddr_in6
, sin6_port
)
442 && sizeof (((struct sockaddr_in
) {}).sin_port
) == sizeof (in_port_t
)
443 && sizeof (((struct sockaddr_in6
) {}).sin6_port
) == sizeof (in_port_t
),
444 "AF_INET and AF_INET6 port consistency");
445 const struct sockaddr_in
*sinp
= (const struct sockaddr_in
*) sa
;
446 if (!(flags
& NI_NUMERICSERV
))
448 struct servent
*s
, ts
;
450 while ((e
= __getservbyport_r (sinp
->sin_port
,
452 ? "udp" : "tcp"), &ts
,
453 tmpbuf
->data
, tmpbuf
->length
, &s
)))
457 if (!scratch_buffer_grow (tmpbuf
))
464 return checked_copy (serv
, servlen
, s
->s_name
);
465 /* Fall through to numeric conversion. */
467 return CHECKED_SNPRINTF (serv
, servlen
, "%d", ntohs (sinp
->sin_port
));
470 /* Convert service to string, AF_LOCAL variant. */
472 gni_serv_local (struct scratch_buffer
*tmpbuf
,
473 const struct sockaddr
*sa
, socklen_t addrlen
,
474 char *serv
, socklen_t servlen
, int flags
)
477 (serv
, servlen
, ((const struct sockaddr_un
*) sa
)->sun_path
);
480 /* Convert service to string, dispatching to the implementations
483 gni_serv (struct scratch_buffer
*tmpbuf
,
484 const struct sockaddr
*sa
, socklen_t addrlen
,
485 char *serv
, socklen_t servlen
, int flags
)
487 switch (sa
->sa_family
)
491 return gni_serv_inet (tmpbuf
, sa
, addrlen
, serv
, servlen
, flags
);
493 return gni_serv_local (tmpbuf
, sa
, addrlen
, serv
, servlen
, flags
);
500 getnameinfo (const struct sockaddr
*sa
, socklen_t addrlen
, char *host
,
501 socklen_t hostlen
, char *serv
, socklen_t servlen
,
504 if (flags
& ~(NI_NUMERICHOST
|NI_NUMERICSERV
|NI_NOFQDN
|NI_NAMEREQD
|NI_DGRAM
505 |NI_IDN
|DEPRECATED_NI_IDN
))
508 if (sa
== NULL
|| addrlen
< sizeof (sa_family_t
))
511 if ((flags
& NI_NAMEREQD
) && host
== NULL
&& serv
== NULL
)
514 switch (sa
->sa_family
)
517 if (addrlen
< (socklen_t
) offsetof (struct sockaddr_un
, sun_path
))
521 if (addrlen
< sizeof (struct sockaddr_in
))
525 if (addrlen
< sizeof (struct sockaddr_in6
))
532 struct scratch_buffer tmpbuf
;
533 scratch_buffer_init (&tmpbuf
);
535 if (host
!= NULL
&& hostlen
> 0)
537 int result
= gni_host (&tmpbuf
, sa
, addrlen
, host
, hostlen
, flags
);
540 scratch_buffer_free (&tmpbuf
);
545 if (serv
&& (servlen
> 0))
547 int result
= gni_serv (&tmpbuf
, sa
, addrlen
, serv
, servlen
, flags
);
550 scratch_buffer_free (&tmpbuf
);
555 scratch_buffer_free (&tmpbuf
);
558 libc_hidden_def (getnameinfo
)