(linenum→info "unix/slp.c:2238")

glibc/2.7/inet/getnameinfo.c

    1: /* The Inner Net License, Version 2.00
    2: 
    3:   The author(s) grant permission for redistribution and use in source and
    4: binary forms, with or without modification, of the software and documentation
    5: provided that the following conditions are met:
    6: 
    7: 0. 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.
   11: 1. All terms of the all other applicable copyrights and licenses must be
   12:    followed.
   13: 2. Redistributions of source code must retain the authors' copyright
   14:    notice(s), this list of conditions, and the following disclaimer.
   15: 3. 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.
   18: 4. [The copyright holder has authorized the removal of this clause.]
   19: 5. 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: 
   23: THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
   24: EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   25: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   26: DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
   27: DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   28: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   30: ANY 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
   32: SOFTWARE, 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 <stddef.h>
   42: #include <stdlib.h>
   43: #include <stdio.h>
   44: #include <string.h>
   45: #include <unistd.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 <bits/libc-lock.h>
   55: 
   56: #ifdef HAVE_LIBIDN
   57: # include <libidn/idna.h>
   58: extern int __idna_to_unicode_lzlz (const char *input, char **output,
   59:                                    int flags);
   60: #endif
   61: 
   62: #ifndef min
   63: # define min(x,y) (((x) > (y)) ? (y) : (x))
   64: #endif /* min */
   65: 
   66: libc_freeres_ptr (static char *domain);
   67: 
   68: 
   69: static char *
   70: internal_function
   71: nrl_domainname (void)
   72: {
   73:   static int not_first;
   74: 
   75:   if (! not_first)
   76:     {
   77:       __libc_lock_define_initialized (static, lock);
   78:       __libc_lock_lock (lock);
   79: 
   80:       if (! not_first)
   81:         {
   82:           char *c;
   83:           struct hostent *h, th;
   84:           size_t tmpbuflen = 1024;
   85:           char *tmpbuf = alloca (tmpbuflen);
   86:           int herror;
   87: 
   88:           not_first = 1;
   89: 
   90:           while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
   91:                                     &herror))
   92:             {
   93:               if (herror == NETDB_INTERNAL && errno == ERANGE)
   94:                 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
   95:               else
   96:                 break;
   97:             }
   98: 
   99:           if (h && (c = strchr (h->h_name, '.')))
  100:             domain = __strdup (++c);
  101:           else
  102:             {
  103:               /* The name contains no domain information.  Use the name
  104:                  now to get more information.  */
  105:               while (__gethostname (tmpbuf, tmpbuflen))
  106:                 tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
  107: 
  108:               if ((c = strchr (tmpbuf, '.')))
  109:                 domain = __strdup (++c);
  110:               else
  111:                 {
  112:                   /* We need to preserve the hostname.  */
  113:                   const char *hstname = strdupa (tmpbuf);
  114: 
  115:                   while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
  116:                                             &h, &herror))
  117:                     {
  118:                       if (herror == NETDB_INTERNAL && errno == ERANGE)
  119:                         tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
  120:                                                 2 * tmpbuflen);
  121:                       else
  122:                         break;
  123:                     }
  124: 
  125:                   if (h && (c = strchr(h->h_name, '.')))
  126:                     domain = __strdup (++c);
  127:                   else
  128:                     {
  129:                       struct in_addr in_addr;
  130: 
  131:                       in_addr.s_addr = htonl (INADDR_LOOPBACK);
  132: 
  133:                       while (__gethostbyaddr_r ((const char *) &in_addr,
  134:                                                 sizeof (struct in_addr),
  135:                                                 AF_INET, &th, tmpbuf,
  136:                                                 tmpbuflen, &h, &herror))
  137:                         {
  138:                           if (herror == NETDB_INTERNAL && errno == ERANGE)
  139:                             tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
  140:                                                     2 * tmpbuflen);
  141:                           else
  142:                             break;
  143:                         }
  144: 
  145:                       if (h && (c = strchr (h->h_name, '.')))
  146:                         domain = __strdup (++c);
  147:                     }
  148:                 }
  149:             }
  150:         }
  151: 
  152:       __libc_lock_unlock (lock);
  153:     }
  154: 
  155:   return domain;
  156: };
  157: 
  158: 
  159: int
  160: getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
  161:              socklen_t hostlen, char *serv, socklen_t servlen,
  162:              unsigned int flags)
  163: {
  164:   int serrno = errno;
  165:   int tmpbuflen = 1024;
  166:   int herrno;
  167:   char *tmpbuf = alloca (tmpbuflen);
  168:   struct hostent th;
  169:   int ok = 0;
  170: 
  171:   if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
  172: #ifdef HAVE_LIBIDN
  173:                 |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
  174: #endif
  175:                 ))
  176:     return EAI_BADFLAGS;
  177: 
  178:   if (sa == NULL || addrlen < sizeof (sa_family_t))
  179:     return EAI_FAMILY;
  180: 
  181:   switch (sa->sa_family)
  182:     {
  183:     case AF_LOCAL:
  184:       if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
  185:         return EAI_FAMILY;
  186:       break;
  187:     case AF_INET:
  188:       if (addrlen < sizeof (struct sockaddr_in))
  189:         return EAI_FAMILY;
  190:       break;
  191:     case AF_INET6:
  192:       if (addrlen < sizeof (struct sockaddr_in6))
  193:         return EAI_FAMILY;
  194:       break;
  195:     default:
  196:       return EAI_FAMILY;
  197:     }
  198: 
  199:   if (host != NULL && hostlen > 0)
  200:     switch (sa->sa_family)
  201:       {
  202:       case AF_INET:
  203:       case AF_INET6:
  204:         if (!(flags & NI_NUMERICHOST))
  205:           {
  206:             struct hostent *h = NULL;
  207:             if (sa->sa_family == AF_INET6)
  208:               {
  209:                 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
  210:                                           sizeof(struct in6_addr),
  211:                                           AF_INET6, &th, tmpbuf, tmpbuflen,
  212:                                           &h, &herrno))
  213:                   if (herrno == NETDB_INTERNAL && errno == ERANGE)
  214:                     tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
  215:                   else
  216:                     break;
  217:               }
  218:             else
  219:               {
  220:                 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
  221:                                           sizeof(struct in_addr), AF_INET,
  222:                                           &th, tmpbuf, tmpbuflen,
  223:                                           &h, &herrno))
  224:                   if (herrno == NETDB_INTERNAL && errno == ERANGE)
  225:                     tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
  226:                   else
  227:                     break;
  228:               }
  229: 
  230:             if (h == NULL)
  231:               {
  232:                 if (herrno == NETDB_INTERNAL)
  233:                   {
  234:                     __set_h_errno (herrno);
  235:                     return EAI_SYSTEM;
  236:                   }
  237:                 if (herrno == TRY_AGAIN)
  238:                   {
  239:                     __set_h_errno (herrno);
  240:                     return EAI_AGAIN;
  241:                   }
  242:               }
  243: 
  244:             if (h)
  245:               {
  246:                 char *c;
  247:                 if ((flags & NI_NOFQDN)
  248:                     && (c = nrl_domainname ())
  249:                     && (c = strstr (h->h_name, c))
  250:                     && (c != h->h_name) && (*(--c) == '.'))
  251:                   /* Terminate the string after the prefix.  */
  252:                   *c = '\0';
  253: 
  254: #ifdef HAVE_LIBIDN
  255:                 /* If requested, convert from the IDN format.  */
  256:                 if (flags & NI_IDN)
  257:                   {
  258:                     int idn_flags = 0;
  259:                     if  (flags & NI_IDN_ALLOW_UNASSIGNED)
  260:                       idn_flags |= IDNA_ALLOW_UNASSIGNED;
  261:                     if (flags & NI_IDN_USE_STD3_ASCII_RULES)
  262:                       idn_flags |= IDNA_USE_STD3_ASCII_RULES;
  263: 
  264:                     char *out;
  265:                     int rc = __idna_to_unicode_lzlz (h->h_name, &out,
  266:                                                      idn_flags);
  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:                       }
  281:                   }
  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;
  291:               }
  292:           }
  293: 
  294:         if (!ok)
  295:           {
  296:             if (flags & NI_NAMEREQD)
  297:               {
  298:                 __set_errno (serrno);
  299:                 return EAI_NONAME;
  300:               }
  301:             else
  302:               {
  303:                 const char *c;
  304:                 if (sa->sa_family == AF_INET6)
  305:                   {
  306:                     const struct sockaddr_in6 *sin6p;
  307:                     uint32_t scopeid;
  308: 
  309:                     sin6p = (const struct sockaddr_in6 *) sa;
  310: 
  311:                     c = inet_ntop (AF_INET6,
  312:                                    (const void *) &sin6p->sin6_addr, host, hostlen);
  313:                     scopeid = sin6p->sin6_scope_id;
  314:                     if (scopeid != 0)
  315:                       {
  316:                         /* Buffer is >= IFNAMSIZ+1.  */
  317:                         char scopebuf[IFNAMSIZ + 1];
  318:                         char *scopeptr;
  319:                         int ni_numericscope = 0;
  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];
  326: 
  327:                         if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
  328:                             || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
  329:                           {
  330:                             if (if_indextoname (scopeid, scopeptr) == NULL)
  331:                               ++ni_numericscope;
  332:                             else
  333:                               scopelen = strlen (scopebuf);
  334:                           }
  335:                         else
  336:                           ++ni_numericscope;
  337: 
  338:                         if (ni_numericscope)
  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);
  350:                       }
  351:                   }
  352:                 else
  353:                   c = inet_ntop (AF_INET,
  354:                                  (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
  355:                                  host, hostlen);
  356:                 if (c == NULL)
  357:                   return EAI_SYSTEM;
  358:               }
  359:             ok = 1;
  360:           }
  361:         break;
  362: 
  363:       case AF_LOCAL:
  364:         if (!(flags & NI_NUMERICHOST))
  365:           {
  366:             struct utsname utsname;
  367: 
  368:             if (!uname (&utsname))
  369:               {
  370:                 strncpy (host, utsname.nodename, hostlen);
  371:                 break;
  372:               };
  373:           };
  374: 
  375:         if (flags & NI_NAMEREQD)
  376:            {
  377:             __set_errno (serrno);
  378:             return EAI_NONAME;
  379:           }
  380: 
  381:         strncpy (host, "localhost", hostlen);
  382:         break;
  383: 
  384:       default:
  385:         return EAI_FAMILY;
  386:     }
  387: 
  388:   if (serv && (servlen > 0))
  389:     switch (sa->sa_family)
  390:       {
  391:       case AF_INET:
  392:       case AF_INET6:
  393:         if (!(flags & NI_NUMERICSERV))
  394:           {
  395:             struct servent *s, ts;
  396:             int e;
  397:             while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
  398:                                            ((flags & NI_DGRAM)
  399:                                             ? "udp" : "tcp"),
  400:                                            &ts, tmpbuf, tmpbuflen, &s)))
  401:               {
  402:                 if (e == ERANGE)
  403:                   tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
  404:                 else
  405:                   break;
  406:               }
  407:             if (s)
  408:               {
  409:                 strncpy (serv, s->s_name, servlen);
  410:                 break;
  411:               }
  412:           }
  413: 
  414:         if (__snprintf (serv, servlen, "%d",
  415:                         ntohs (((const struct sockaddr_in *) sa)->sin_port))
  416:             + 1 > servlen)
  417:           return EAI_OVERFLOW;
  418: 
  419:         break;
  420: 
  421:       case AF_LOCAL:
  422:         strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
  423:         break;
  424:     }
  425: 
  426:   if (host && (hostlen > 0))
  427:     host[hostlen-1] = 0;
  428:   if (serv && (servlen > 0))
  429:     serv[servlen-1] = 0;
  430:   errno = serrno;
  431:   return 0;
  432: }
  433: libc_hidden_def (getnameinfo)
Syntax (Markdown)