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.
184. [The copyright holder has authorized the removal of this clause.]
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
38#include <errno.h>
39#include <netdb.h>
40#include <stddef.h>
41#include <stdlib.h>
42#include <stdio.h>
43#include <string.h>
44#include <unistd.h>
45#include <stdint.h>
46#include <arpa/inet.h>
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 <libc-lock.h>
55#include <scratch_buffer.h>
56
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
63#ifndef min
64# define min(x,y) (((x) > (y)) ? (y) : (x))
65#endif /* min */
66
67libc_freeres_ptr (static char *domain);
68
69
70static char *
71internal_function
72nrl_domainname (void)
73{
74 static int not_first;
75
76 if (! not_first)
77 {
78 __libc_lock_define_initialized (static, lock);
79 __libc_lock_lock (lock);
80
81 if (! not_first)
82 {
83 char *c;
84 struct hostent *h, th;
85 int herror;
86 struct scratch_buffer tmpbuf;
87
88 scratch_buffer_init (&tmpbuf);
89 not_first = 1;
90
91 while (__gethostbyname_r ("localhost", &th,
92 tmpbuf.data, tmpbuf.length,
93 &h, &herror))
94 {
95 if (herror == NETDB_INTERNAL && errno == ERANGE)
96 {
97 if (!scratch_buffer_grow (&tmpbuf))
98 goto done;
99 }
100 else
101 break;
102 }
103
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. */
110 while (__gethostname (tmpbuf.data, tmpbuf.length))
111 if (!scratch_buffer_grow (&tmpbuf))
112 goto done;
113
114 if ((c = strchr (tmpbuf.data, '.')))
115 domain = __strdup (++c);
116 else
117 {
118 /* We need to preserve the hostname. */
119 const char *hstname = strdupa (tmpbuf.data);
120
121 while (__gethostbyname_r (hstname, &th,
122 tmpbuf.data, tmpbuf.length,
123 &h, &herror))
124 {
125 if (herror == NETDB_INTERNAL && errno == ERANGE)
126 {
127 if (!scratch_buffer_grow (&tmpbuf))
128 goto done;
129 }
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
140 in_addr.s_addr = htonl (INADDR_LOOPBACK);
141
142 while (__gethostbyaddr_r ((const char *) &in_addr,
143 sizeof (struct in_addr),
144 AF_INET, &th,
145 tmpbuf.data, tmpbuf.length,
146 &h, &herror))
147 {
148 if (herror == NETDB_INTERNAL && errno == ERANGE)
149 {
150 if (!scratch_buffer_grow (&tmpbuf))
151 goto done;
152 }
153 else
154 break;
155 }
156
157 if (h && (c = strchr (h->h_name, '.')))
158 domain = __strdup (++c);
159 }
160 }
161 }
162 done:
163 scratch_buffer_free (&tmpbuf);
164 }
165
166 __libc_lock_unlock (lock);
167 }
168
169 return domain;
170};
171
172
173int
174getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
175 socklen_t hostlen, char *serv, socklen_t servlen,
176 int flags)
177{
178 int serrno = errno;
179 int herrno;
180 struct hostent th;
181 int ok = 0;
182 struct scratch_buffer tmpbuf;
183
184 scratch_buffer_init (&tmpbuf);
185
186 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
187#ifdef HAVE_LIBIDN
188 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
189#endif
190 ))
191 return EAI_BADFLAGS;
192
193 if (sa == NULL || addrlen < sizeof (sa_family_t))
194 return EAI_FAMILY;
195
196 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
197 return EAI_NONAME;
198
199 switch (sa->sa_family)
200 {
201 case AF_LOCAL:
202 if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
203 return EAI_FAMILY;
204 break;
205 case AF_INET:
206 if (addrlen < sizeof (struct sockaddr_in))
207 return EAI_FAMILY;
208 break;
209 case AF_INET6:
210 if (addrlen < sizeof (struct sockaddr_in6))
211 return EAI_FAMILY;
212 break;
213 default:
214 return EAI_FAMILY;
215 }
216
217 if (host != NULL && hostlen > 0)
218 switch (sa->sa_family)
219 {
220 case AF_INET:
221 case AF_INET6:
222 if (!(flags & NI_NUMERICHOST))
223 {
224 struct hostent *h = NULL;
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),
229 AF_INET6, &th,
230 tmpbuf.data, tmpbuf.length,
231 &h, &herrno))
232 if (herrno == NETDB_INTERNAL && errno == ERANGE)
233 {
234 if (!scratch_buffer_grow (&tmpbuf))
235 {
236 __set_h_errno (herrno);
237 return EAI_MEMORY;
238 }
239 }
240 else
241 break;
242 }
243 else
244 {
245 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
246 sizeof(struct in_addr),
247 AF_INET, &th,
248 tmpbuf.data, tmpbuf.length,
249 &h, &herrno))
250 if (herrno == NETDB_INTERNAL && errno == ERANGE)
251 {
252 if (!scratch_buffer_grow (&tmpbuf))
253 {
254 __set_h_errno (herrno);
255 return EAI_MEMORY;
256 }
257 }
258 else
259 break;
260 }
261
262 if (h == NULL)
263 {
264 if (herrno == NETDB_INTERNAL)
265 {
266 __set_h_errno (herrno);
267 return EAI_SYSTEM;
268 }
269 if (herrno == TRY_AGAIN)
270 {
271 __set_h_errno (herrno);
272 return EAI_AGAIN;
273 }
274 }
275
276 if (h)
277 {
278 char *c;
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. */
284 *c = '\0';
285
286#ifdef HAVE_LIBIDN
287 /* If requested, convert from the IDN format. */
288 if (flags & NI_IDN)
289 {
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
296 char *out;
297 int rc = __idna_to_unicode_lzlz (h->h_name, &out,
298 idn_flags);
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 }
313 }
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;
323 }
324 }
325
326 if (!ok)
327 {
328 if (flags & NI_NAMEREQD)
329 {
330 __set_errno (serrno);
331 return EAI_NONAME;
332 }
333 else
334 {
335 const char *c;
336 if (sa->sa_family == AF_INET6)
337 {
338 const struct sockaddr_in6 *sin6p;
339 uint32_t scopeid;
340
341 sin6p = (const struct sockaddr_in6 *) sa;
342
343 c = inet_ntop (AF_INET6,
344 (const void *) &sin6p->sin6_addr, host, hostlen);
345 scopeid = sin6p->sin6_scope_id;
346 if (scopeid != 0)
347 {
348 /* Buffer is >= IFNAMSIZ+1. */
349 char scopebuf[IFNAMSIZ + 1];
350 char *scopeptr;
351 int ni_numericscope = 0;
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];
358
359 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
360 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
361 {
362 if (if_indextoname (scopeid, scopeptr) == NULL)
363 ++ni_numericscope;
364 else
365 scopelen = strlen (scopebuf);
366 }
367 else
368 ++ni_numericscope;
369
370 if (ni_numericscope)
371 scopelen = 1 + __snprintf (scopeptr,
372 (scopebuf
373 + sizeof scopebuf
374 - scopeptr),
375 "%u", scopeid);
376
377 if (real_hostlen + scopelen + 1 > hostlen)
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);
383 }
384 }
385 else
386 c = inet_ntop (AF_INET,
387 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
388 host, hostlen);
389 if (c == NULL)
390 return EAI_OVERFLOW;
391 }
392 ok = 1;
393 }
394 break;
395
396 case AF_LOCAL:
397 if (!(flags & NI_NUMERICHOST))
398 {
399 struct utsname utsname;
400
401 if (!uname (&utsname))
402 {
403 strncpy (host, utsname.nodename, hostlen);
404 break;
405 };
406 };
407
408 if (flags & NI_NAMEREQD)
409 {
410 __set_errno (serrno);
411 return EAI_NONAME;
412 }
413
414 strncpy (host, "localhost", hostlen);
415 break;
416
417 default:
418 return EAI_FAMILY;
419 }
420
421 if (serv && (servlen > 0))
422 switch (sa->sa_family)
423 {
424 case AF_INET:
425 case AF_INET6:
426 if (!(flags & NI_NUMERICSERV))
427 {
428 struct servent *s, ts;
429 int e;
430 while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
431 ((flags & NI_DGRAM)
432 ? "udp" : "tcp"), &ts,
433 tmpbuf.data, tmpbuf.length, &s)))
434 {
435 if (e == ERANGE)
436 {
437 if (!scratch_buffer_grow (&tmpbuf))
438 return EAI_MEMORY;
439 }
440 else
441 break;
442 }
443 if (s)
444 {
445 strncpy (serv, s->s_name, servlen);
446 break;
447 }
448 }
449
450 if (__snprintf (serv, servlen, "%d",
451 ntohs (((const struct sockaddr_in *) sa)->sin_port))
452 + 1 > servlen)
453 return EAI_OVERFLOW;
454
455 break;
456
457 case AF_LOCAL:
458 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
459 break;
460 }
461
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;
468}
469libc_hidden_def (getnameinfo)
470