]> git.ipfire.org Git - thirdparty/glibc.git/blame - inet/getnameinfo.c
Update.
[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
c0bc5f7b 38#include <alloca.h>
1fb05e3d 39#include <errno.h>
c0bc5f7b 40#include <netdb.h>
6ac36398 41#include <stdlib.h>
1fb05e3d 42#include <stdio.h>
c0bc5f7b 43#include <string.h>
1fb05e3d 44#include <unistd.h>
5a97622d 45#include <arpa/inet.h>
c0bc5f7b
UD
46#include <net/if.h>
47#include <netinet/in.h>
48#include <sys/param.h>
49#include <sys/socket.h>
50#include <sys/types.h>
51#include <sys/un.h>
52#include <sys/utsname.h>
53#include <bits/libc-lock.h>
1fb05e3d 54
ab0fcbfa
UD
55#ifdef HAVE_LIBIDN
56# include <libidn/idna.h>
57extern int __idna_to_unicode_lzlz (const char *input, char **output,
58 int flags);
59#endif
60
1fb05e3d 61#ifndef min
cd6ede75 62# define min(x,y) (((x) > (y)) ? (y) : (x))
1fb05e3d
UD
63#endif /* min */
64
0d297437
UD
65libc_freeres_ptr (static char *domain);
66
1fb05e3d 67
40a55d20 68static char *
dfd2257a 69internal_function
cd6ede75 70nrl_domainname (void)
1fb05e3d 71{
390500b1 72 static int not_first;
1fb05e3d 73
3a07823a 74 if (! not_first)
cd6ede75
UD
75 {
76 __libc_lock_define_initialized (static, lock);
77 __libc_lock_lock (lock);
78
3a07823a 79 if (! not_first)
cd6ede75
UD
80 {
81 char *c;
82 struct hostent *h, th;
40a55d20 83 size_t tmpbuflen = 1024;
cd6ede75
UD
84 char *tmpbuf = alloca (tmpbuflen);
85 int herror;
86
390500b1 87 not_first = 1;
cd6ede75
UD
88
89 while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
90 &herror))
91 {
92 if (herror == NETDB_INTERNAL && errno == ERANGE)
218d76e0 93 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
cd6ede75
UD
94 else
95 break;
96 }
5a97622d 97
cd6ede75
UD
98 if (h && (c = strchr (h->h_name, '.')))
99 domain = __strdup (++c);
100 else
101 {
102 /* The name contains no domain information. Use the name
103 now to get more information. */
50304ef0 104 while (__gethostname (tmpbuf, tmpbuflen))
218d76e0 105 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
5a97622d 106
cd6ede75
UD
107 if ((c = strchr (tmpbuf, '.')))
108 domain = __strdup (++c);
109 else
110 {
111 /* We need to preserve the hostname. */
112 const char *hstname = strdupa (tmpbuf);
113
114 while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
115 &h, &herror))
116 {
117 if (herror == NETDB_INTERNAL && errno == ERANGE)
218d76e0
UD
118 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
119 2 * tmpbuflen);
cd6ede75
UD
120 else
121 break;
122 }
123
124 if (h && (c = strchr(h->h_name, '.')))
125 domain = __strdup (++c);
126 else
127 {
128 struct in_addr in_addr;
129
062a2a18 130 in_addr.s_addr = htonl (INADDR_LOOPBACK);
cd6ede75
UD
131
132 while (__gethostbyaddr_r ((const char *) &in_addr,
133 sizeof (struct in_addr),
134 AF_INET, &th, tmpbuf,
135 tmpbuflen, &h, &herror))
136 {
137 if (herror == NETDB_INTERNAL && errno == ERANGE)
218d76e0
UD
138 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
139 2 * tmpbuflen);
cd6ede75
UD
140 else
141 break;
142 }
143
144 if (h && (c = strchr (h->h_name, '.')))
145 domain = __strdup (++c);
146 }
147 }
5a97622d 148 }
5a97622d 149 }
1fb05e3d 150
cd6ede75 151 __libc_lock_unlock (lock);
1fb05e3d
UD
152 }
153
1fb05e3d
UD
154 return domain;
155};
156
cd6ede75
UD
157
158int
c7614ee9 159getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
ccd4b479
UD
160 socklen_t hostlen, char *serv, socklen_t servlen,
161 unsigned int flags)
1fb05e3d
UD
162{
163 int serrno = errno;
5a97622d
UD
164 int tmpbuflen = 1024;
165 int herrno;
cd6ede75 166 char *tmpbuf = alloca (tmpbuflen);
5a97622d 167 struct hostent th;
c0bc5f7b 168 int ok = 0;
1fb05e3d 169
ab0fcbfa
UD
170 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
171#ifdef HAVE_LIBIDN
172 |NI_IDN
173#endif
174 ))
85599e53
UD
175 return EAI_BADFLAGS;
176
922809a2 177 if (sa == NULL || addrlen < sizeof (sa_family_t))
85599e53 178 return EAI_FAMILY;
922809a2
UD
179
180 switch (sa->sa_family)
181 {
182 case AF_LOCAL:
4fcddf8e 183 if (addrlen < (socklen_t) (((struct sockaddr_un *) NULL)->sun_path))
85599e53 184 return EAI_FAMILY;
4fcddf8e
UD
185 break;
186 case AF_INET:
187 if (addrlen < sizeof (struct sockaddr_in))
85599e53 188 return EAI_FAMILY;
4fcddf8e
UD
189 break;
190 case AF_INET6:
191 if (addrlen < sizeof (struct sockaddr_in6))
85599e53 192 return EAI_FAMILY;
922809a2
UD
193 break;
194 default:
85599e53 195 return EAI_FAMILY;
922809a2 196 }
1fb05e3d 197
cd6ede75 198 if (host != NULL && hostlen > 0)
4fcddf8e 199 switch (sa->sa_family)
cd6ede75 200 {
1fb05e3d 201 case AF_INET:
1fb05e3d 202 case AF_INET6:
cd6ede75
UD
203 if (!(flags & NI_NUMERICHOST))
204 {
205 struct hostent *h = NULL;
cd6ede75
UD
206 if (h == NULL)
207 {
cd6ede75
UD
208 if (sa->sa_family == AF_INET6)
209 {
c3301189 210 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
cd6ede75
UD
211 sizeof(struct in6_addr),
212 AF_INET6, &th, tmpbuf, tmpbuflen,
213 &h, &herrno))
214 {
215 if (herrno == NETDB_INTERNAL)
216 {
217 if (errno == ERANGE)
218d76e0
UD
218 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
219 2 * tmpbuflen);
cd6ede75
UD
220 else
221 {
222 __set_h_errno (herrno);
40a55d20 223 __set_errno (serrno);
85599e53 224 return EAI_SYSTEM;
cd6ede75
UD
225 }
226 }
227 else
228 {
229 break;
230 }
231 }
5a97622d 232 }
cd6ede75
UD
233 else
234 {
c3301189 235 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
cd6ede75
UD
236 sizeof(struct in_addr), AF_INET,
237 &th, tmpbuf, tmpbuflen,
238 &h, &herrno))
239 {
240 if (errno == ERANGE)
218d76e0
UD
241 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
242 2 * tmpbuflen);
cd6ede75
UD
243 else
244 {
245 break;
246 }
247 }
248 }
5a97622d 249 }
1fb05e3d 250
cd6ede75
UD
251 if (h)
252 {
85599e53 253 char *c;
104d0bd3 254 if ((flags & NI_NOFQDN)
85599e53
UD
255 && (c = nrl_domainname ())
256 && (c = strstr (h->h_name, c))
257 && (c != h->h_name) && (*(--c) == '.'))
ab0fcbfa
UD
258 /* Terminate the string after the prefix. */
259 *c = '\0';
260
261#ifdef HAVE_LIBIDN
262 /* If requested, convert from the IDN format. */
263 if (flags & NI_IDN)
cd6ede75 264 {
ab0fcbfa
UD
265 char *out;
266 int rc = __idna_to_unicode_lzlz (h->h_name, &out, 0);
267 if (rc != IDNA_SUCCESS)
268 {
269 if (rc == IDNA_MALLOC_ERROR)
270 return EAI_MEMORY;
271 if (rc == IDNA_DLOPEN_ERROR)
272 return EAI_SYSTEM;
273 return EAI_IDN_ENCODE;
274 }
275
276 if (out != h->h_name)
277 {
278 h->h_name = strdupa (out);
279 free (out);
280 }
cd6ede75 281 }
ab0fcbfa
UD
282#endif
283
284 size_t len = strlen (h->h_name) + 1;
285 if (len > hostlen)
286 return EAI_OVERFLOW;
287
288 memcpy (host, h->h_name, len);
289
290 ok = 1;
cd6ede75
UD
291 }
292 }
1fb05e3d 293
c0bc5f7b 294 if (!ok)
40a55d20 295 {
c0bc5f7b 296 if (flags & NI_NAMEREQD)
40a55d20
UD
297 {
298 __set_errno (serrno);
85599e53 299 return EAI_NONAME;
40a55d20 300 }
c0bc5f7b
UD
301 else
302 {
303 const char *c;
304 if (sa->sa_family == AF_INET6)
305 {
c3301189 306 const struct sockaddr_in6 *sin6p;
c0bc5f7b
UD
307 uint32_t scopeid;
308
c3301189
UD
309 sin6p = (const struct sockaddr_in6 *) sa;
310
c0bc5f7b 311 c = inet_ntop (AF_INET6,
c3301189 312 (const void *) &sin6p->sin6_addr, host, hostlen);
85599e53
UD
313 scopeid = sin6p->sin6_scope_id;
314 if (scopeid != 0)
c0bc5f7b
UD
315 {
316 /* Buffer is >= IFNAMSIZ+1. */
4fcddf8e 317 char scopebuf[IFNAMSIZ + 1];
85599e53 318 char *scopeptr;
c0bc5f7b 319 int ni_numericscope = 0;
85599e53
UD
320 size_t real_hostlen = __strnlen (host, hostlen);
321 size_t scopelen = 0;
322
323 scopebuf[0] = SCOPE_DELIMITER;
324 scopebuf[1] = '\0';
325 scopeptr = &scopebuf[1];
c0bc5f7b
UD
326
327 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
328 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
329 {
5804f16c 330 if (if_indextoname (scopeid, scopeptr) == NULL)
c0bc5f7b 331 ++ni_numericscope;
85599e53
UD
332 else
333 scopelen = strlen (scopebuf);
c0bc5f7b
UD
334 }
335 else
336 ++ni_numericscope;
337
338 if (ni_numericscope)
85599e53
UD
339 scopelen = 1 + __snprintf (scopeptr,
340 (scopebuf
341 + sizeof scopebuf
342 - scopeptr),
343 "%u", scopeid);
344
345 if (real_hostlen + scopelen + 1 > hostlen)
346 /* XXX We should not fail here. Simply enlarge
347 the buffer or return with out of memory. */
348 return EAI_SYSTEM;
349 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
c0bc5f7b
UD
350 }
351 }
352 else
353 c = inet_ntop (AF_INET,
c3301189 354 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
c0bc5f7b
UD
355 host, hostlen);
356 if (c == NULL)
357 {
358 __set_errno (serrno);
85599e53 359 return EAI_SYSTEM;
c0bc5f7b
UD
360 }
361 }
362 ok = 1;
cd6ede75 363 }
1fb05e3d 364 break;
cd6ede75 365
1fb05e3d 366 case AF_LOCAL:
cd6ede75
UD
367 if (!(flags & NI_NUMERICHOST))
368 {
369 struct utsname utsname;
1fb05e3d 370
cd6ede75
UD
371 if (!uname (&utsname))
372 {
373 strncpy (host, utsname.nodename, hostlen);
374 break;
375 };
1fb05e3d 376 };
1fb05e3d
UD
377
378 if (flags & NI_NAMEREQD)
40a55d20
UD
379 {
380 __set_errno (serrno);
85599e53 381 return EAI_NONAME;
40a55d20 382 }
1fb05e3d 383
cd6ede75 384 strncpy (host, "localhost", hostlen);
1fb05e3d 385 break;
cd6ede75 386
1fb05e3d 387 default:
85599e53 388 return EAI_FAMILY;
cd6ede75 389 }
1fb05e3d
UD
390
391 if (serv && (servlen > 0))
4fcddf8e 392 switch (sa->sa_family)
cd6ede75 393 {
1fb05e3d 394 case AF_INET:
1fb05e3d 395 case AF_INET6:
cd6ede75
UD
396 if (!(flags & NI_NUMERICSERV))
397 {
398 struct servent *s, ts;
c3301189 399 while (__getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
cd6ede75
UD
400 ((flags & NI_DGRAM) ? "udp" : "tcp"),
401 &ts, tmpbuf, tmpbuflen, &s))
402 {
403 if (herrno == NETDB_INTERNAL)
404 {
405 if (errno == ERANGE)
218d76e0
UD
406 tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
407 2 * tmpbuflen);
cd6ede75 408 else
40a55d20
UD
409 {
410 __set_errno (serrno);
85599e53 411 return EAI_SYSTEM;
40a55d20 412 }
cd6ede75
UD
413 }
414 else
415 {
416 break;
417 }
418 }
419 if (s)
420 {
40a55d20 421 strncpy (serv, s->s_name, servlen);
cd6ede75 422 break;
5a97622d 423 }
5a97622d 424 }
ab0fcbfa
UD
425
426 if (__snprintf (serv, servlen, "%d",
427 ntohs (((const struct sockaddr_in *) sa)->sin_port))
428 + 1 > servlen)
429 return EAI_OVERFLOW;
430
1fb05e3d 431 break;
cd6ede75 432
1fb05e3d 433 case AF_LOCAL:
c3301189 434 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1fb05e3d 435 break;
cd6ede75
UD
436 }
437
1fb05e3d
UD
438 if (host && (hostlen > 0))
439 host[hostlen-1] = 0;
440 if (serv && (servlen > 0))
441 serv[servlen-1] = 0;
442 errno = serrno;
443 return 0;
40a55d20 444}
9b0b40d3 445libc_hidden_def (getnameinfo)