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
11 1. All terms of the all other applicable copyrights and licenses must be
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. */
46 #include <arpa/inet.h>
48 #include <netinet/in.h>
49 #include <sys/param.h>
50 #include <sys/socket.h>
51 #include <sys/types.h>
53 #include <sys/utsname.h>
54 #include <bits/libc-lock.h>
55 #include <scratch_buffer.h>
58 # include <libidn/idna.h>
59 extern int __idna_to_unicode_lzlz (const char *input
, char **output
,
64 # define min(x,y) (((x) > (y)) ? (y) : (x))
67 libc_freeres_ptr (static char *domain
);
78 __libc_lock_define_initialized (static, lock
);
79 __libc_lock_lock (lock
);
84 struct hostent
*h
, th
;
86 struct scratch_buffer tmpbuf
;
88 scratch_buffer_init (&tmpbuf
);
91 while (__gethostbyname_r ("localhost", &th
,
92 tmpbuf
.data
, tmpbuf
.length
,
95 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
97 if (!scratch_buffer_grow (&tmpbuf
))
104 if (h
&& (c
= strchr (h
->h_name
, '.')))
105 domain
= __strdup (++c
);
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
))
114 if ((c
= strchr (tmpbuf
.data
, '.')))
115 domain
= __strdup (++c
);
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
,
125 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
127 if (!scratch_buffer_grow (&tmpbuf
))
134 if (h
&& (c
= strchr(h
->h_name
, '.')))
135 domain
= __strdup (++c
);
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
),
145 tmpbuf
.data
, tmpbuf
.length
,
148 if (herror
== NETDB_INTERNAL
&& errno
== ERANGE
)
150 if (!scratch_buffer_grow (&tmpbuf
))
157 if (h
&& (c
= strchr (h
->h_name
, '.')))
158 domain
= __strdup (++c
);
163 scratch_buffer_free (&tmpbuf
);
166 __libc_lock_unlock (lock
);
174 getnameinfo (const struct sockaddr
*sa
, socklen_t addrlen
, char *host
,
175 socklen_t hostlen
, char *serv
, socklen_t servlen
,
182 struct scratch_buffer tmpbuf
;
184 scratch_buffer_init (&tmpbuf
);
186 if (flags
& ~(NI_NUMERICHOST
|NI_NUMERICSERV
|NI_NOFQDN
|NI_NAMEREQD
|NI_DGRAM
188 |NI_IDN
|NI_IDN_ALLOW_UNASSIGNED
|NI_IDN_USE_STD3_ASCII_RULES
193 if (sa
== NULL
|| addrlen
< sizeof (sa_family_t
))
196 if ((flags
& NI_NAMEREQD
) && host
== NULL
&& serv
== NULL
)
199 switch (sa
->sa_family
)
202 if (addrlen
< (socklen_t
) offsetof (struct sockaddr_un
, sun_path
))
206 if (addrlen
< sizeof (struct sockaddr_in
))
210 if (addrlen
< sizeof (struct sockaddr_in6
))
217 if (host
!= NULL
&& hostlen
> 0)
218 switch (sa
->sa_family
)
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
),
230 tmpbuf
.data
, tmpbuf
.length
,
232 if (herrno
== NETDB_INTERNAL
&& errno
== ERANGE
)
234 if (!scratch_buffer_grow (&tmpbuf
))
236 __set_h_errno (herrno
);
245 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in
*)sa
)->sin_addr
),
246 sizeof(struct in_addr
),
248 tmpbuf
.data
, tmpbuf
.length
,
250 if (herrno
== NETDB_INTERNAL
&& errno
== ERANGE
)
252 if (!scratch_buffer_grow (&tmpbuf
))
254 __set_h_errno (herrno
);
264 if (herrno
== NETDB_INTERNAL
)
266 __set_h_errno (herrno
);
269 if (herrno
== TRY_AGAIN
)
271 __set_h_errno (herrno
);
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. */
287 /* If requested, convert from the IDN format. */
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
;
297 int rc
= __idna_to_unicode_lzlz (h
->h_name
, &out
,
299 if (rc
!= IDNA_SUCCESS
)
301 if (rc
== IDNA_MALLOC_ERROR
)
303 if (rc
== IDNA_DLOPEN_ERROR
)
305 return EAI_IDN_ENCODE
;
308 if (out
!= h
->h_name
)
310 h
->h_name
= strdupa (out
);
316 size_t len
= strlen (h
->h_name
) + 1;
320 memcpy (host
, h
->h_name
, len
);
328 if (flags
& NI_NAMEREQD
)
330 __set_errno (serrno
);
336 if (sa
->sa_family
== AF_INET6
)
338 const struct sockaddr_in6
*sin6p
;
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
;
348 /* Buffer is >= IFNAMSIZ+1. */
349 char scopebuf
[IFNAMSIZ
+ 1];
351 int ni_numericscope
= 0;
352 size_t real_hostlen
= __strnlen (host
, hostlen
);
355 scopebuf
[0] = SCOPE_DELIMITER
;
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
)
365 scopelen
= strlen (scopebuf
);
371 scopelen
= 1 + __snprintf (scopeptr
,
377 if (real_hostlen
+ scopelen
+ 1 > hostlen
)
378 /* Signal the buffer is too small. This is
379 what inet_ntop does. */
382 memcpy (host
+ real_hostlen
, scopebuf
, scopelen
+ 1);
386 c
= inet_ntop (AF_INET
,
387 (const void *) &(((const struct sockaddr_in
*) sa
)->sin_addr
),
397 if (!(flags
& NI_NUMERICHOST
))
399 struct utsname utsname
;
401 if (!uname (&utsname
))
403 strncpy (host
, utsname
.nodename
, hostlen
);
408 if (flags
& NI_NAMEREQD
)
410 __set_errno (serrno
);
414 strncpy (host
, "localhost", hostlen
);
421 if (serv
&& (servlen
> 0))
422 switch (sa
->sa_family
)
426 if (!(flags
& NI_NUMERICSERV
))
428 struct servent
*s
, ts
;
430 while ((e
= __getservbyport_r (((const struct sockaddr_in
*) sa
)->sin_port
,
432 ? "udp" : "tcp"), &ts
,
433 tmpbuf
.data
, tmpbuf
.length
, &s
)))
437 if (!scratch_buffer_grow (&tmpbuf
))
445 strncpy (serv
, s
->s_name
, servlen
);
450 if (__snprintf (serv
, servlen
, "%d",
451 ntohs (((const struct sockaddr_in
*) sa
)->sin_port
))
458 strncpy (serv
, ((const struct sockaddr_un
*) sa
)->sun_path
, servlen
);
462 if (host
&& (hostlen
> 0))
464 if (serv
&& (servlen
> 0))
469 libc_hidden_def (getnameinfo
)