source: trunk/libs/newlib/src/newlib/libc/sys/linux/net/getnameinfo.c @ 444

Last change on this file since 444 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

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