]> git.ipfire.org Git - thirdparty/glibc.git/blame - inet/getnameinfo.c
BZ#18921: Mark fixed in NEWS.
[thirdparty/glibc.git] / inet / getnameinfo.c
CommitLineData
1fb05e3d
UD
1/* The Inner Net License, Version 2.00
2
3 The author(s) grant permission for redistribution and use in source and
4binary forms, with or without modification, of the software and documentation
5provided that the following conditions are met:
6
70. 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
10 way or form.
111. All terms of the all other applicable copyrights and licenses must be
12 followed.
132. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
153. 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.
aeb25823 184. [The copyright holder has authorized the removal of this clause.]
1fb05e3d
UD
195. 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.
22
23THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30ANY 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
32SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 If these license terms cause you a real problem, contact the author. */
35
36/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
37
1fb05e3d 38#include <errno.h>
c0bc5f7b 39#include <netdb.h>
965cba04 40#include <stddef.h>
6ac36398 41#include <stdlib.h>
1fb05e3d 42#include <stdio.h>
c0bc5f7b 43#include <string.h>
1fb05e3d 44#include <unistd.h>
e054f494 45#include <stdint.h>
5a97622d 46#include <arpa/inet.h>
c0bc5f7b
UD
47#include <net/if.h>
48#include <netinet/in.h>
49#include <sys/param.h>
50#include <sys/socket.h>
51#include <sys/types.h>
52#include <sys/un.h>
53#include <sys/utsname.h>
54#include <bits/libc-lock.h>
c6ee40da 55#include <scratch_buffer.h>
1fb05e3d 56
ab0fcbfa
UD
57#ifdef HAVE_LIBIDN
58# include <libidn/idna.h>
59extern int __idna_to_unicode_lzlz (const char *input, char **output,
60 int flags);
61#endif
62
1fb05e3d 63#ifndef min
cd6ede75 64# define min(x,y) (((x) > (y)) ? (y) : (x))
1fb05e3d
UD
65#endif /* min */
66
0d297437
UD
67libc_freeres_ptr (static char *domain);
68
1fb05e3d 69
40a55d20 70static char *
dfd2257a 71internal_function
cd6ede75 72nrl_domainname (void)
1fb05e3d 73{
390500b1 74 static int not_first;
1fb05e3d 75
3a07823a 76 if (! not_first)
cd6ede75
UD
77 {
78 __libc_lock_define_initialized (static, lock);
79 __libc_lock_lock (lock);
80
3a07823a 81 if (! not_first)
cd6ede75
UD
82 {
83 char *c;
84 struct hostent *h, th;
cd6ede75 85 int herror;
c6ee40da 86 struct scratch_buffer tmpbuf;
cd6ede75 87
c6ee40da 88 scratch_buffer_init (&tmpbuf);
390500b1 89 not_first = 1;
cd6ede75 90
c6ee40da
FW
91 while (__gethostbyname_r ("localhost", &th,
92 tmpbuf.data, tmpbuf.length,
93 &h, &herror))
cd6ede75
UD
94 {
95 if (herror == NETDB_INTERNAL && errno == ERANGE)
c6ee40da
FW
96 {
97 if (!scratch_buffer_grow (&tmpbuf))
98 goto done;
99 }
cd6ede75
UD
100 else
101 break;
102 }
5a97622d 103
cd6ede75
UD
104 if (h && (c = strchr (h->h_name, '.')))
105 domain = __strdup (++c);
106 else
107 {
108 /* The name contains no domain information. Use the name
109 now to get more information. */
c6ee40da
FW
110 while (__gethostname (tmpbuf.data, tmpbuf.length))
111 if (!scratch_buffer_grow (&tmpbuf))
112 goto done;
5a97622d 113
c6ee40da 114 if ((c = strchr (tmpbuf.data, '.')))
cd6ede75
UD
115 domain = __strdup (++c);
116 else
117 {
118 /* We need to preserve the hostname. */
c6ee40da 119 const char *hstname = strdupa (tmpbuf.data);
cd6ede75 120
c6ee40da
FW
121 while (__gethostbyname_r (hstname, &th,
122 tmpbuf.data, tmpbuf.length,
cd6ede75
UD
123 &h, &herror))
124 {
125 if (herror == NETDB_INTERNAL && errno == ERANGE)
c6ee40da
FW
126 {
127 if (!scratch_buffer_grow (&tmpbuf))
128 goto done;
129 }
cd6ede75
UD
130 else
131 break;
132 }
133
134 if (h && (c = strchr(h->h_name, '.')))
135 domain = __strdup (++c);
136 else
137 {
138 struct in_addr in_addr;
139
062a2a18 140 in_addr.s_addr = htonl (INADDR_LOOPBACK);
cd6ede75
UD
141
142 while (__gethostbyaddr_r ((const char *) &in_addr,
143 sizeof (struct in_addr),
c6ee40da
FW
144 AF_INET, &th,
145 tmpbuf.data, tmpbuf.length,
146 &h, &herror))
cd6ede75
UD
147 {
148 if (herror == NETDB_INTERNAL && errno == ERANGE)
c6ee40da
FW
149 {
150 if (!scratch_buffer_grow (&tmpbuf))
151 goto done;
152 }
cd6ede75
UD
153 else
154 break;
155 }
156
157 if (h && (c = strchr (h->h_name, '.')))
158 domain = __strdup (++c);
159 }
160 }
5a97622d 161 }
c6ee40da
FW
162 done:
163 scratch_buffer_free (&tmpbuf);
5a97622d 164 }
1fb05e3d 165
cd6ede75 166 __libc_lock_unlock (lock);
1fb05e3d
UD
167 }
168
1fb05e3d
UD
169 return domain;
170};
171
cd6ede75
UD
172
173int
c7614ee9 174getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
ccd4b479 175 socklen_t hostlen, char *serv, socklen_t servlen,
e4ecafe0 176 int flags)
1fb05e3d
UD
177{
178 int serrno = errno;
5a97622d 179 int herrno;
5a97622d 180 struct hostent th;
c0bc5f7b 181 int ok = 0;
c6ee40da
FW
182 struct scratch_buffer tmpbuf;
183
184 scratch_buffer_init (&tmpbuf);
1fb05e3d 185
ab0fcbfa
UD
186 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
187#ifdef HAVE_LIBIDN
3a0e90bd 188 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
ab0fcbfa
UD
189#endif
190 ))
85599e53
UD
191 return EAI_BADFLAGS;
192
922809a2 193 if (sa == NULL || addrlen < sizeof (sa_family_t))
85599e53 194 return EAI_FAMILY;
922809a2 195
d4f0720b
UD
196 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
197 return EAI_NONAME;
198
922809a2
UD
199 switch (sa->sa_family)
200 {
201 case AF_LOCAL:
965cba04 202 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
85599e53 203 return EAI_FAMILY;
4fcddf8e
UD
204 break;
205 case AF_INET:
206 if (addrlen < sizeof (struct sockaddr_in))
85599e53 207 return EAI_FAMILY;
4fcddf8e
UD
208 break;
209 case AF_INET6:
210 if (addrlen < sizeof (struct sockaddr_in6))
85599e53 211 return EAI_FAMILY;
922809a2
UD
212 break;
213 default:
85599e53 214 return EAI_FAMILY;
922809a2 215 }
1fb05e3d 216
cd6ede75 217 if (host != NULL && hostlen > 0)
4fcddf8e 218 switch (sa->sa_family)
cd6ede75 219 {
1fb05e3d 220 case AF_INET:
1fb05e3d 221 case AF_INET6:
cd6ede75
UD
222 if (!(flags & NI_NUMERICHOST))
223 {
224 struct hostent *h = NULL;
6e310111
UD
225 if (sa->sa_family == AF_INET6)
226 {
227 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
228 sizeof(struct in6_addr),
c6ee40da
FW
229 AF_INET6, &th,
230 tmpbuf.data, tmpbuf.length,
6e310111
UD
231 &h, &herrno))
232 if (herrno == NETDB_INTERNAL && errno == ERANGE)
c6ee40da
FW
233 {
234 if (!scratch_buffer_grow (&tmpbuf))
235 {
236 __set_h_errno (herrno);
237 return EAI_MEMORY;
238 }
239 }
6e310111
UD
240 else
241 break;
242 }
243 else
244 {
245 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
c6ee40da
FW
246 sizeof(struct in_addr),
247 AF_INET, &th,
248 tmpbuf.data, tmpbuf.length,
6e310111
UD
249 &h, &herrno))
250 if (herrno == NETDB_INTERNAL && errno == ERANGE)
c6ee40da
FW
251 {
252 if (!scratch_buffer_grow (&tmpbuf))
253 {
254 __set_h_errno (herrno);
255 return EAI_MEMORY;
256 }
257 }
6e310111
UD
258 else
259 break;
260 }
261
cd6ede75
UD
262 if (h == NULL)
263 {
6e310111 264 if (herrno == NETDB_INTERNAL)
cd6ede75 265 {
6e310111
UD
266 __set_h_errno (herrno);
267 return EAI_SYSTEM;
5a97622d 268 }
6e310111 269 if (herrno == TRY_AGAIN)
cd6ede75 270 {
6e310111
UD
271 __set_h_errno (herrno);
272 return EAI_AGAIN;
cd6ede75 273 }
5a97622d 274 }
1fb05e3d 275
cd6ede75
UD
276 if (h)
277 {
85599e53 278 char *c;
104d0bd3 279 if ((flags & NI_NOFQDN)
85599e53
UD
280 && (c = nrl_domainname ())
281 && (c = strstr (h->h_name, c))
282 && (c != h->h_name) && (*(--c) == '.'))
ab0fcbfa
UD
283 /* Terminate the string after the prefix. */
284 *c = '\0';
285
286#ifdef HAVE_LIBIDN
287 /* If requested, convert from the IDN format. */
288 if (flags & NI_IDN)
cd6ede75 289 {
3a0e90bd
UD
290 int idn_flags = 0;
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;
295
ab0fcbfa 296 char *out;
3a0e90bd
UD
297 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
298 idn_flags);
ab0fcbfa
UD
299 if (rc != IDNA_SUCCESS)
300 {
301 if (rc == IDNA_MALLOC_ERROR)
302 return EAI_MEMORY;
303 if (rc == IDNA_DLOPEN_ERROR)
304 return EAI_SYSTEM;
305 return EAI_IDN_ENCODE;
306 }
307
308 if (out != h->h_name)
309 {
310 h->h_name = strdupa (out);
311 free (out);
312 }
cd6ede75 313 }
ab0fcbfa
UD
314#endif
315
316 size_t len = strlen (h->h_name) + 1;
317 if (len > hostlen)
318 return EAI_OVERFLOW;
319
320 memcpy (host, h->h_name, len);
321
322 ok = 1;
cd6ede75
UD
323 }
324 }
1fb05e3d 325
c0bc5f7b 326 if (!ok)
40a55d20 327 {
c0bc5f7b 328 if (flags & NI_NAMEREQD)
40a55d20
UD
329 {
330 __set_errno (serrno);
85599e53 331 return EAI_NONAME;
40a55d20 332 }
c0bc5f7b
UD
333 else
334 {
335 const char *c;
336 if (sa->sa_family == AF_INET6)
337 {
c3301189 338 const struct sockaddr_in6 *sin6p;
c0bc5f7b
UD
339 uint32_t scopeid;
340
c3301189
UD
341 sin6p = (const struct sockaddr_in6 *) sa;
342
c0bc5f7b 343 c = inet_ntop (AF_INET6,
c3301189 344 (const void *) &sin6p->sin6_addr, host, hostlen);
85599e53
UD
345 scopeid = sin6p->sin6_scope_id;
346 if (scopeid != 0)
c0bc5f7b
UD
347 {
348 /* Buffer is >= IFNAMSIZ+1. */
4fcddf8e 349 char scopebuf[IFNAMSIZ + 1];
85599e53 350 char *scopeptr;
c0bc5f7b 351 int ni_numericscope = 0;
85599e53
UD
352 size_t real_hostlen = __strnlen (host, hostlen);
353 size_t scopelen = 0;
354
355 scopebuf[0] = SCOPE_DELIMITER;
356 scopebuf[1] = '\0';
357 scopeptr = &scopebuf[1];
c0bc5f7b
UD
358
359 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
360 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
361 {
5804f16c 362 if (if_indextoname (scopeid, scopeptr) == NULL)
c0bc5f7b 363 ++ni_numericscope;
85599e53
UD
364 else
365 scopelen = strlen (scopebuf);
c0bc5f7b
UD
366 }
367 else
368 ++ni_numericscope;
369
370 if (ni_numericscope)
85599e53
UD
371 scopelen = 1 + __snprintf (scopeptr,
372 (scopebuf
373 + sizeof scopebuf
374 - scopeptr),
375 "%u", scopeid);
376
377 if (real_hostlen + scopelen + 1 > hostlen)
27deeafc
UD
378 /* Signal the buffer is too small. This is
379 what inet_ntop does. */
380 c = NULL;
381 else
382 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
c0bc5f7b
UD
383 }
384 }
385 else
386 c = inet_ntop (AF_INET,
c3301189 387 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
c0bc5f7b
UD
388 host, hostlen);
389 if (c == NULL)
27deeafc 390 return EAI_OVERFLOW;
c0bc5f7b
UD
391 }
392 ok = 1;
cd6ede75 393 }
1fb05e3d 394 break;
cd6ede75 395
1fb05e3d 396 case AF_LOCAL:
cd6ede75
UD
397 if (!(flags & NI_NUMERICHOST))
398 {
399 struct utsname utsname;
1fb05e3d 400
cd6ede75
UD
401 if (!uname (&utsname))
402 {
403 strncpy (host, utsname.nodename, hostlen);
404 break;
405 };
1fb05e3d 406 };
1fb05e3d
UD
407
408 if (flags & NI_NAMEREQD)
40a55d20
UD
409 {
410 __set_errno (serrno);
85599e53 411 return EAI_NONAME;
40a55d20 412 }
1fb05e3d 413
cd6ede75 414 strncpy (host, "localhost", hostlen);
1fb05e3d 415 break;
cd6ede75 416
1fb05e3d 417 default:
e4ecafe0 418 return EAI_FAMILY;
cd6ede75 419 }
1fb05e3d
UD
420
421 if (serv && (servlen > 0))
4fcddf8e 422 switch (sa->sa_family)
cd6ede75 423 {
1fb05e3d 424 case AF_INET:
1fb05e3d 425 case AF_INET6:
cd6ede75
UD
426 if (!(flags & NI_NUMERICSERV))
427 {
428 struct servent *s, ts;
0292b0dd
UD
429 int e;
430 while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
431 ((flags & NI_DGRAM)
c6ee40da
FW
432 ? "udp" : "tcp"), &ts,
433 tmpbuf.data, tmpbuf.length, &s)))
cd6ede75 434 {
0292b0dd 435 if (e == ERANGE)
c6ee40da
FW
436 {
437 if (!scratch_buffer_grow (&tmpbuf))
438 return EAI_MEMORY;
439 }
cd6ede75 440 else
0292b0dd 441 break;
cd6ede75
UD
442 }
443 if (s)
444 {
40a55d20 445 strncpy (serv, s->s_name, servlen);
cd6ede75 446 break;
5a97622d 447 }
5a97622d 448 }
ab0fcbfa
UD
449
450 if (__snprintf (serv, servlen, "%d",
451 ntohs (((const struct sockaddr_in *) sa)->sin_port))
452 + 1 > servlen)
453 return EAI_OVERFLOW;
454
1fb05e3d 455 break;
cd6ede75 456
1fb05e3d 457 case AF_LOCAL:
c3301189 458 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1fb05e3d 459 break;
cd6ede75
UD
460 }
461
1fb05e3d
UD
462 if (host && (hostlen > 0))
463 host[hostlen-1] = 0;
464 if (serv && (servlen > 0))
465 serv[servlen-1] = 0;
466 errno = serrno;
467 return 0;
40a55d20 468}
9b0b40d3 469libc_hidden_def (getnameinfo)