1/* Convert socket address to string using Name Service Switch modules.
2 Copyright (C) 1997-2017 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
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.
364. [The copyright holder has authorized the removal of this clause.]
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
56#include <errno.h>
57#include <netdb.h>
58#include <stddef.h>
59#include <stdlib.h>
60#include <stdio.h>
61#include <string.h>
62#include <unistd.h>
63#include <stdint.h>
64#include <arpa/inet.h>
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>
72#include <libc-lock.h>
73#include <scratch_buffer.h>
74
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
81#ifndef min
82# define min(x,y) (((x) > (y)) ? (y) : (x))
83#endif /* min */
84
85libc_freeres_ptr (static char *domain);
86
87
88static char *
89internal_function
90nrl_domainname (void)
91{
92 static int not_first;
93
94 if (! not_first)
95 {
96 __libc_lock_define_initialized (static, lock);
97 __libc_lock_lock (lock);
98
99 if (! not_first)
100 {
101 char *c;
102 struct hostent *h, th;
103 int herror;
104 struct scratch_buffer tmpbuf;
105
106 scratch_buffer_init (&tmpbuf);
107 not_first = 1;
108
109 while (__gethostbyname_r ("localhost", &th,
110 tmpbuf.data, tmpbuf.length,
111 &h, &herror))
112 {
113 if (herror == NETDB_INTERNAL && errno == ERANGE)
114 {
115 if (!scratch_buffer_grow (&tmpbuf))
116 goto done;
117 }
118 else
119 break;
120 }
121
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. */
128 while (__gethostname (tmpbuf.data, tmpbuf.length))
129 if (!scratch_buffer_grow (&tmpbuf))
130 goto done;
131
132 if ((c = strchr (tmpbuf.data, '.')))
133 domain = __strdup (++c);
134 else
135 {
136 /* We need to preserve the hostname. */
137 const char *hstname = strdupa (tmpbuf.data);
138
139 while (__gethostbyname_r (hstname, &th,
140 tmpbuf.data, tmpbuf.length,
141 &h, &herror))
142 {
143 if (herror == NETDB_INTERNAL && errno == ERANGE)
144 {
145 if (!scratch_buffer_grow (&tmpbuf))
146 goto done;
147 }
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
158 in_addr.s_addr = htonl (INADDR_LOOPBACK);
159
160 while (__gethostbyaddr_r ((const char *) &in_addr,
161 sizeof (struct in_addr),
162 AF_INET, &th,
163 tmpbuf.data, tmpbuf.length,
164 &h, &herror))
165 {
166 if (herror == NETDB_INTERNAL && errno == ERANGE)
167 {
168 if (!scratch_buffer_grow (&tmpbuf))
169 goto done;
170 }
171 else
172 break;
173 }
174
175 if (h && (c = strchr (h->h_name, '.')))
176 domain = __strdup (++c);
177 }
178 }
179 }
180 done:
181 scratch_buffer_free (&tmpbuf);
182 }
183
184 __libc_lock_unlock (lock);
185 }
186
187 return domain;
188};
189
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
192 success. */
193static int
194checked_copy (char *dest, size_t destlen, const char *source)
195{
196 size_t source_length = strlen (source);
197 if (source_length + 1 > destlen)
198 return EAI_OVERFLOW;
199 memcpy (dest, source, source_length + 1);
200 return 0;
201}
202
203/* Helper function for CHECKED_SNPRINTF below. */
204static int
205check_sprintf_result (int result, size_t destlen)
206{
207 if (result < 0)
208 return EAI_SYSTEM;
209 if ((size_t) result >= destlen)
210 /* If ret == destlen, there was no room for the terminating NUL
211 character. */
212 return EAI_OVERFLOW;
213 return 0;
214}
215
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
218 other error. */
219#define CHECKED_SNPRINTF(dest, destlen, format, ...) \
220 check_sprintf_result \
221 (__snprintf (dest, destlen, format, __VA_ARGS__), destlen)
222
223/* Convert host name, AF_INET/AF_INET6 case, name only. */
224static int
225gni_host_inet_name (struct scratch_buffer *tmpbuf,
226 const struct sockaddr *sa, socklen_t addrlen,
227 char *host, socklen_t hostlen, int flags)
228{
229 int herrno;
230 struct hostent th;
231 struct hostent *h = NULL;
232 if (sa->sa_family == AF_INET6)
233 {
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,
237 &h, &herrno))
238 if (herrno == NETDB_INTERNAL && errno == ERANGE)
239 {
240 if (!scratch_buffer_grow (tmpbuf))
241 {
242 __set_h_errno (herrno);
243 return EAI_MEMORY;
244 }
245 }
246 else
247 break;
248 }
249 else
250 {
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,
254 &h, &herrno))
255 if (herrno == NETDB_INTERNAL && errno == ERANGE)
256 {
257 if (!scratch_buffer_grow (tmpbuf))
258 {
259 __set_h_errno (herrno);
260 return EAI_MEMORY;
261 }
262 }
263 else
264 break;
265 }
266
267 if (h == NULL)
268 {
269 if (herrno == NETDB_INTERNAL)
270 {
271 __set_h_errno (herrno);
272 return EAI_SYSTEM;
273 }
274 if (herrno == TRY_AGAIN)
275 {
276 __set_h_errno (herrno);
277 return EAI_AGAIN;
278 }
279 }
280
281 if (h)
282 {
283 char *c;
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. */
289 *c = '\0';
290
291#ifdef HAVE_LIBIDN
292 /* If requested, convert from the IDN format. */
293 if (flags & NI_IDN)
294 {
295 int idn_flags = 0;
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;
300
301 char *out;
302 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
303 idn_flags);
304 if (rc != IDNA_SUCCESS)
305 {
306 if (rc == IDNA_MALLOC_ERROR)
307 return EAI_MEMORY;
308 if (rc == IDNA_DLOPEN_ERROR)
309 return EAI_SYSTEM;
310 return EAI_IDN_ENCODE;
311 }
312
313 if (out != h->h_name)
314 {
315 h->h_name = strdupa (out);
316 free (out);
317 }
318 }
319#endif
320
321 size_t len = strlen (h->h_name) + 1;
322 if (len > hostlen)
323 return EAI_OVERFLOW;
324
325 memcpy (host, h->h_name, len);
326
327 return 0;
328 }
329
330 return EAI_NONAME;
331}
332
333/* Convert host name, AF_INET/AF_INET6 case, numeric conversion. */
334static int
335gni_host_inet_numeric (struct scratch_buffer *tmpbuf,
336 const struct sockaddr *sa, socklen_t addrlen,
337 char *host, socklen_t hostlen, int flags)
338{
339 if (sa->sa_family == AF_INET6)
340 {
341 const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
342 if (inet_ntop (AF_INET6, &sin6p->sin6_addr, host, hostlen) == NULL)
343 return EAI_OVERFLOW;
344
345 uint32_t scopeid = sin6p->sin6_scope_id;
346 if (scopeid != 0)
347 {
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;
352
353 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
354 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
355 {
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);
361 }
362 return CHECKED_SNPRINTF
363 (scope_start, scope_length, "%c%u", SCOPE_DELIMITER, scopeid);
364 }
365 }
366 else
367 {
368 const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
369 if (inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen) == NULL)
370 return EAI_OVERFLOW;
371 }
372 return 0;
373}
374
375/* Convert AF_INET or AF_INET6 socket address, host part. */
376static int
377gni_host_inet (struct scratch_buffer *tmpbuf,
378 const struct sockaddr *sa, socklen_t addrlen,
379 char *host, socklen_t hostlen, int flags)
380{
381 if (!(flags & NI_NUMERICHOST))
382 {
383 int result = gni_host_inet_name
384 (tmpbuf, sa, addrlen, host, hostlen, flags);
385 if (result != EAI_NONAME)
386 return result;
387 }
388
389 if (flags & NI_NAMEREQD)
390 return EAI_NONAME;
391 else
392 return gni_host_inet_numeric
393 (tmpbuf, sa, addrlen, host, hostlen, flags);
394}
395
396/* Convert AF_LOCAL socket address, host part. */
397static int
398gni_host_local (struct scratch_buffer *tmpbuf,
399 const struct sockaddr *sa, socklen_t addrlen,
400 char *host, socklen_t hostlen, int flags)
401{
402 if (!(flags & NI_NUMERICHOST))
403 {
404 struct utsname utsname;
405 if (uname (&utsname) == 0)
406 return checked_copy (host, hostlen, utsname.nodename);
407 }
408
409 if (flags & NI_NAMEREQD)
410 return EAI_NONAME;
411
412 return checked_copy (host, hostlen, "localhost");
413}
414
415/* Convert the host part of an AF_LOCAK socket address. */
416static int
417gni_host (struct scratch_buffer *tmpbuf,
418 const struct sockaddr *sa, socklen_t addrlen,
419 char *host, socklen_t hostlen, int flags)
420{
421 switch (sa->sa_family)
422 {
423 case AF_INET:
424 case AF_INET6:
425 return gni_host_inet (tmpbuf, sa, addrlen, host, hostlen, flags);
426
427 case AF_LOCAL:
428 return gni_host_local (tmpbuf, sa, addrlen, host, hostlen, flags);
429
430 default:
431 return EAI_FAMILY;
432 }
433}
434
435/* Convert service to string, AF_INET and AF_INET6 variant. */
436static int
437gni_serv_inet (struct scratch_buffer *tmpbuf,
438 const struct sockaddr *sa, socklen_t addrlen,
439 char *serv, socklen_t servlen, int flags)
440{
441 _Static_assert
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))
449 {
450 struct servent *s, ts;
451 int e;
452 while ((e = __getservbyport_r (sinp->sin_port,
453 ((flags & NI_DGRAM)
454 ? "udp" : "tcp"), &ts,
455 tmpbuf->data, tmpbuf->length, &s)))
456 {
457 if (e == ERANGE)
458 {
459 if (!scratch_buffer_grow (tmpbuf))
460 return EAI_MEMORY;
461 }
462 else
463 break;
464 }
465 if (s)
466 return checked_copy (serv, servlen, s->s_name);
467 /* Fall through to numeric conversion. */
468 }
469 return CHECKED_SNPRINTF (serv, servlen, "%d", ntohs (sinp->sin_port));
470}
471
472/* Convert service to string, AF_LOCAL variant. */
473static int
474gni_serv_local (struct scratch_buffer *tmpbuf,
475 const struct sockaddr *sa, socklen_t addrlen,
476 char *serv, socklen_t servlen, int flags)
477{
478 return checked_copy
479 (serv, servlen, ((const struct sockaddr_un *) sa)->sun_path);
480}
481
482/* Convert service to string, dispatching to the implementations
483 above. */
484static int
485gni_serv (struct scratch_buffer *tmpbuf,
486 const struct sockaddr *sa, socklen_t addrlen,
487 char *serv, socklen_t servlen, int flags)
488{
489 switch (sa->sa_family)
490 {
491 case AF_INET:
492 case AF_INET6:
493 return gni_serv_inet (tmpbuf, sa, addrlen, serv, servlen, flags);
494 case AF_LOCAL:
495 return gni_serv_local (tmpbuf, sa, addrlen, serv, servlen, flags);
496 default:
497 return EAI_FAMILY;
498 }
499}
500
501int
502getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
503 socklen_t hostlen, char *serv, socklen_t servlen,
504 int flags)
505{
506 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
507#ifdef HAVE_LIBIDN
508 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
509#endif
510 ))
511 return EAI_BADFLAGS;
512
513 if (sa == NULL || addrlen < sizeof (sa_family_t))
514 return EAI_FAMILY;
515
516 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
517 return EAI_NONAME;
518
519 switch (sa->sa_family)
520 {
521 case AF_LOCAL:
522 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
523 return EAI_FAMILY;
524 break;
525 case AF_INET:
526 if (addrlen < sizeof (struct sockaddr_in))
527 return EAI_FAMILY;
528 break;
529 case AF_INET6:
530 if (addrlen < sizeof (struct sockaddr_in6))
531 return EAI_FAMILY;
532 break;
533 default:
534 return EAI_FAMILY;
535 }
536
537 struct scratch_buffer tmpbuf;
538 scratch_buffer_init (&tmpbuf);
539
540 if (host != NULL && hostlen > 0)
541 {
542 int result = gni_host (&tmpbuf, sa, addrlen, host, hostlen, flags);
543 if (result != 0)
544 {
545 scratch_buffer_free (&tmpbuf);
546 return result;
547 }
548 }
549
550 if (serv && (servlen > 0))
551 {
552 int result = gni_serv (&tmpbuf, sa, addrlen, serv, servlen, flags);
553 if (result != 0)
554 {
555 scratch_buffer_free (&tmpbuf);
556 return result;
557 }
558 }
559
560 scratch_buffer_free (&tmpbuf);
561 return 0;
562}
563libc_hidden_def (getnameinfo)
564