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