Home | History | Annotate | Download | only in cups
      1 /*
      2  * HTTP address routines for CUPS.
      3  *
      4  * Copyright 2007-2014 by Apple Inc.
      5  * Copyright 1997-2006 by Easy Software Products, all rights reserved.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /*
     17  * Include necessary headers...
     18  */
     19 
     20 #include "cups-private.h"
     21 #include <sys/stat.h>
     22 #ifdef HAVE_RESOLV_H
     23 #  include <resolv.h>
     24 #endif /* HAVE_RESOLV_H */
     25 #ifdef __APPLE__
     26 #  include <CoreFoundation/CoreFoundation.h>
     27 #  include <SystemConfiguration/SystemConfiguration.h>
     28 #endif /* __APPLE__ */
     29 
     30 
     31 /*
     32  * 'httpAddrAny()' - Check for the "any" address.
     33  *
     34  * @since CUPS 1.2/macOS 10.5@
     35  */
     36 
     37 int					/* O - 1 if "any", 0 otherwise */
     38 httpAddrAny(const http_addr_t *addr)	/* I - Address to check */
     39 {
     40   if (!addr)
     41     return (0);
     42 
     43 #ifdef AF_INET6
     44   if (addr->addr.sa_family == AF_INET6 &&
     45       IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
     46     return (1);
     47 #endif /* AF_INET6 */
     48 
     49   if (addr->addr.sa_family == AF_INET &&
     50       ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
     51     return (1);
     52 
     53   return (0);
     54 }
     55 
     56 
     57 /*
     58  * 'httpAddrClose()' - Close a socket created by @link httpAddrConnect@ or
     59  *                     @link httpAddrListen@.
     60  *
     61  * Pass @code NULL@ for sockets created with @link httpAddrConnect@ and the
     62  * listen address for sockets created with @link httpAddrListen@. This will
     63  * ensure that domain sockets are removed when closed.
     64  *
     65  * @since CUPS 2.0/OS 10.10@
     66  */
     67 
     68 int						/* O - 0 on success, -1 on failure */
     69 httpAddrClose(http_addr_t *addr,		/* I - Listen address or @code NULL@ */
     70               int         fd)			/* I - Socket file descriptor */
     71 {
     72 #ifdef WIN32
     73   if (closesocket(fd))
     74 #else
     75   if (close(fd))
     76 #endif /* WIN32 */
     77     return (-1);
     78 
     79 #ifdef AF_LOCAL
     80   if (addr && addr->addr.sa_family == AF_LOCAL)
     81     return (unlink(addr->un.sun_path));
     82 #endif /* AF_LOCAL */
     83 
     84   return (0);
     85 }
     86 
     87 
     88 /*
     89  * 'httpAddrEqual()' - Compare two addresses.
     90  *
     91  * @since CUPS 1.2/macOS 10.5@
     92  */
     93 
     94 int						/* O - 1 if equal, 0 if not */
     95 httpAddrEqual(const http_addr_t *addr1,		/* I - First address */
     96               const http_addr_t *addr2)		/* I - Second address */
     97 {
     98   if (!addr1 && !addr2)
     99     return (1);
    100 
    101   if (!addr1 || !addr2)
    102     return (0);
    103 
    104   if (addr1->addr.sa_family != addr2->addr.sa_family)
    105     return (0);
    106 
    107 #ifdef AF_LOCAL
    108   if (addr1->addr.sa_family == AF_LOCAL)
    109     return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
    110 #endif /* AF_LOCAL */
    111 
    112 #ifdef AF_INET6
    113   if (addr1->addr.sa_family == AF_INET6)
    114     return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16));
    115 #endif /* AF_INET6 */
    116 
    117   return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
    118 }
    119 
    120 
    121 /*
    122  * 'httpAddrLength()' - Return the length of the address in bytes.
    123  *
    124  * @since CUPS 1.2/macOS 10.5@
    125  */
    126 
    127 int					/* O - Length in bytes */
    128 httpAddrLength(const http_addr_t *addr)	/* I - Address */
    129 {
    130   if (!addr)
    131     return (0);
    132 
    133 #ifdef AF_INET6
    134   if (addr->addr.sa_family == AF_INET6)
    135     return (sizeof(addr->ipv6));
    136   else
    137 #endif /* AF_INET6 */
    138 #ifdef AF_LOCAL
    139   if (addr->addr.sa_family == AF_LOCAL)
    140     return ((int)(offsetof(struct sockaddr_un, sun_path) + strlen(addr->un.sun_path) + 1));
    141   else
    142 #endif /* AF_LOCAL */
    143   if (addr->addr.sa_family == AF_INET)
    144     return (sizeof(addr->ipv4));
    145   else
    146     return (0);
    147 
    148 }
    149 
    150 
    151 /*
    152  * 'httpAddrListen()' - Create a listening socket bound to the specified
    153  *                      address and port.
    154  *
    155  * @since CUPS 1.7/macOS 10.9@
    156  */
    157 
    158 int					/* O - Socket or -1 on error */
    159 httpAddrListen(http_addr_t *addr,	/* I - Address to bind to */
    160                int         port)	/* I - Port number to bind to */
    161 {
    162   int		fd = -1,		/* Socket */
    163 		val,			/* Socket value */
    164                 status;			/* Bind status */
    165 
    166 
    167  /*
    168   * Range check input...
    169   */
    170 
    171   if (!addr || port < 0)
    172     return (-1);
    173 
    174  /*
    175   * Create the socket and set options...
    176   */
    177 
    178   if ((fd = socket(addr->addr.sa_family, SOCK_STREAM, 0)) < 0)
    179   {
    180     _cupsSetHTTPError(HTTP_STATUS_ERROR);
    181     return (-1);
    182   }
    183 
    184   val = 1;
    185   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
    186 
    187 #ifdef IPV6_V6ONLY
    188   if (addr->addr.sa_family == AF_INET6)
    189     setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val));
    190 #endif /* IPV6_V6ONLY */
    191 
    192  /*
    193   * Bind the socket...
    194   */
    195 
    196 #ifdef AF_LOCAL
    197   if (addr->addr.sa_family == AF_LOCAL)
    198   {
    199     mode_t	mask;			/* Umask setting */
    200 
    201    /*
    202     * Remove any existing domain socket file...
    203     */
    204 
    205     unlink(addr->un.sun_path);
    206 
    207    /*
    208     * Save the current umask and set it to 0 so that all users can access
    209     * the domain socket...
    210     */
    211 
    212     mask = umask(0);
    213 
    214    /*
    215     * Bind the domain socket...
    216     */
    217 
    218     status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr));
    219 
    220    /*
    221     * Restore the umask and fix permissions...
    222     */
    223 
    224     umask(mask);
    225     chmod(addr->un.sun_path, 0140777);
    226   }
    227   else
    228 #endif /* AF_LOCAL */
    229   {
    230     _httpAddrSetPort(addr, port);
    231 
    232     status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr));
    233   }
    234 
    235   if (status)
    236   {
    237     _cupsSetHTTPError(HTTP_STATUS_ERROR);
    238 
    239     close(fd);
    240 
    241     return (-1);
    242   }
    243 
    244  /*
    245   * Listen...
    246   */
    247 
    248   if (listen(fd, 5))
    249   {
    250     _cupsSetHTTPError(HTTP_STATUS_ERROR);
    251 
    252     close(fd);
    253 
    254     return (-1);
    255   }
    256 
    257  /*
    258   * Close on exec...
    259   */
    260 
    261 #ifndef WIN32
    262   fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
    263 #endif /* !WIN32 */
    264 
    265 #ifdef SO_NOSIGPIPE
    266  /*
    267   * Disable SIGPIPE for this socket.
    268   */
    269 
    270   val = 1;
    271   setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
    272 #endif /* SO_NOSIGPIPE */
    273 
    274   return (fd);
    275 }
    276 
    277 
    278 /*
    279  * 'httpAddrLocalhost()' - Check for the local loopback address.
    280  *
    281  * @since CUPS 1.2/macOS 10.5@
    282  */
    283 
    284 int					/* O - 1 if local host, 0 otherwise */
    285 httpAddrLocalhost(
    286     const http_addr_t *addr)		/* I - Address to check */
    287 {
    288   if (!addr)
    289     return (1);
    290 
    291 #ifdef AF_INET6
    292   if (addr->addr.sa_family == AF_INET6 &&
    293       IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
    294     return (1);
    295 #endif /* AF_INET6 */
    296 
    297 #ifdef AF_LOCAL
    298   if (addr->addr.sa_family == AF_LOCAL)
    299     return (1);
    300 #endif /* AF_LOCAL */
    301 
    302   if (addr->addr.sa_family == AF_INET &&
    303       (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000)
    304     return (1);
    305 
    306   return (0);
    307 }
    308 
    309 
    310 /*
    311  * 'httpAddrLookup()' - Lookup the hostname associated with the address.
    312  *
    313  * @since CUPS 1.2/macOS 10.5@
    314  */
    315 
    316 char *					/* O - Host name */
    317 httpAddrLookup(
    318     const http_addr_t *addr,		/* I - Address to lookup */
    319     char              *name,		/* I - Host name buffer */
    320     int               namelen)		/* I - Size of name buffer */
    321 {
    322   _cups_globals_t	*cg = _cupsGlobals();
    323 					/* Global data */
    324 
    325 
    326   DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", (void *)addr, (void *)name, namelen));
    327 
    328  /*
    329   * Range check input...
    330   */
    331 
    332   if (!addr || !name || namelen <= 2)
    333   {
    334     if (name && namelen >= 1)
    335       *name = '\0';
    336 
    337     return (NULL);
    338   }
    339 
    340 #ifdef AF_LOCAL
    341   if (addr->addr.sa_family == AF_LOCAL)
    342   {
    343     strlcpy(name, addr->un.sun_path, (size_t)namelen);
    344     return (name);
    345   }
    346 #endif /* AF_LOCAL */
    347 
    348  /*
    349   * Optimize lookups for localhost/loopback addresses...
    350   */
    351 
    352   if (httpAddrLocalhost(addr))
    353   {
    354     strlcpy(name, "localhost", (size_t)namelen);
    355     return (name);
    356   }
    357 
    358 #ifdef HAVE_RES_INIT
    359  /*
    360   * STR #2920: Initialize resolver after failure in cups-polld
    361   *
    362   * If the previous lookup failed, re-initialize the resolver to prevent
    363   * temporary network errors from persisting.  This *should* be handled by
    364   * the resolver libraries, but apparently the glibc folks do not agree.
    365   *
    366   * We set a flag at the end of this function if we encounter an error that
    367   * requires reinitialization of the resolver functions.  We then call
    368   * res_init() if the flag is set on the next call here or in httpAddrLookup().
    369   */
    370 
    371   if (cg->need_res_init)
    372   {
    373     res_init();
    374 
    375     cg->need_res_init = 0;
    376   }
    377 #endif /* HAVE_RES_INIT */
    378 
    379 #ifdef HAVE_GETNAMEINFO
    380   {
    381    /*
    382     * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN
    383     *
    384     * FWIW, I think this is really a bug in the implementation of
    385     * getnameinfo(), but falling back on httpAddrString() is easy to
    386     * do...
    387     */
    388 
    389     int error = getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), name, (socklen_t)namelen, NULL, 0, 0);
    390 
    391     if (error)
    392     {
    393       if (error == EAI_FAIL)
    394         cg->need_res_init = 1;
    395 
    396       return (httpAddrString(addr, name, namelen));
    397     }
    398   }
    399 #else
    400   {
    401     struct hostent	*host;			/* Host from name service */
    402 
    403 
    404 #  ifdef AF_INET6
    405     if (addr->addr.sa_family == AF_INET6)
    406       host = gethostbyaddr((char *)&(addr->ipv6.sin6_addr),
    407                 	   sizeof(struct in_addr), AF_INET6);
    408     else
    409 #  endif /* AF_INET6 */
    410     host = gethostbyaddr((char *)&(addr->ipv4.sin_addr),
    411                 	 sizeof(struct in_addr), AF_INET);
    412 
    413     if (host == NULL)
    414     {
    415      /*
    416       * No hostname, so return the raw address...
    417       */
    418 
    419       if (h_errno == NO_RECOVERY)
    420         cg->need_res_init = 1;
    421 
    422       return (httpAddrString(addr, name, namelen));
    423     }
    424 
    425     strlcpy(name, host->h_name, (size_t)namelen);
    426   }
    427 #endif /* HAVE_GETNAMEINFO */
    428 
    429   DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name));
    430 
    431   return (name);
    432 }
    433 
    434 
    435 /*
    436  * 'httpAddrFamily()' - Get the address family of an address.
    437  */
    438 
    439 int					/* O - Address family */
    440 httpAddrFamily(http_addr_t *addr)	/* I - Address */
    441 {
    442   if (addr)
    443     return (addr->addr.sa_family);
    444   else
    445     return (0);
    446 }
    447 
    448 
    449 /*
    450  * 'httpAddrPort()' - Get the port number associated with an address.
    451  *
    452  * @since CUPS 1.7/macOS 10.9@
    453  */
    454 
    455 int					/* O - Port number */
    456 httpAddrPort(http_addr_t *addr)		/* I - Address */
    457 {
    458   if (!addr)
    459     return (-1);
    460 #ifdef AF_INET6
    461   else if (addr->addr.sa_family == AF_INET6)
    462     return (ntohs(addr->ipv6.sin6_port));
    463 #endif /* AF_INET6 */
    464   else if (addr->addr.sa_family == AF_INET)
    465     return (ntohs(addr->ipv4.sin_port));
    466   else
    467     return (0);
    468 }
    469 
    470 
    471 /*
    472  * '_httpAddrSetPort()' - Set the port number associated with an address.
    473  */
    474 
    475 void
    476 _httpAddrSetPort(http_addr_t *addr,	/* I - Address */
    477                  int         port)	/* I - Port */
    478 {
    479   if (!addr || port <= 0)
    480     return;
    481 
    482 #ifdef AF_INET6
    483   if (addr->addr.sa_family == AF_INET6)
    484     addr->ipv6.sin6_port = htons(port);
    485   else
    486 #endif /* AF_INET6 */
    487   if (addr->addr.sa_family == AF_INET)
    488     addr->ipv4.sin_port = htons(port);
    489 }
    490 
    491 
    492 /*
    493  * 'httpAddrString()' - Convert an address to a numeric string.
    494  *
    495  * @since CUPS 1.2/macOS 10.5@
    496  */
    497 
    498 char *					/* O - Numeric address string */
    499 httpAddrString(const http_addr_t *addr,	/* I - Address to convert */
    500                char              *s,	/* I - String buffer */
    501 	       int               slen)	/* I - Length of string */
    502 {
    503   DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", (void *)addr, (void *)s, slen));
    504 
    505  /*
    506   * Range check input...
    507   */
    508 
    509   if (!addr || !s || slen <= 2)
    510   {
    511     if (s && slen >= 1)
    512       *s = '\0';
    513 
    514     return (NULL);
    515   }
    516 
    517 #ifdef AF_LOCAL
    518   if (addr->addr.sa_family == AF_LOCAL)
    519   {
    520     if (addr->un.sun_path[0] == '/')
    521       strlcpy(s, addr->un.sun_path, (size_t)slen);
    522     else
    523       strlcpy(s, "localhost", (size_t)slen);
    524   }
    525   else
    526 #endif /* AF_LOCAL */
    527   if (addr->addr.sa_family == AF_INET)
    528   {
    529     unsigned temp;			/* Temporary address */
    530 
    531     temp = ntohl(addr->ipv4.sin_addr.s_addr);
    532 
    533     snprintf(s, (size_t)slen, "%d.%d.%d.%d", (temp >> 24) & 255,
    534              (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
    535   }
    536 #ifdef AF_INET6
    537   else if (addr->addr.sa_family == AF_INET6)
    538   {
    539     char	*sptr,			/* Pointer into string */
    540 		temps[64];		/* Temporary string for address */
    541 
    542 #  ifdef HAVE_GETNAMEINFO
    543     if (getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), temps, sizeof(temps), NULL, 0, NI_NUMERICHOST))
    544     {
    545      /*
    546       * If we get an error back, then the address type is not supported
    547       * and we should zero out the buffer...
    548       */
    549 
    550       s[0] = '\0';
    551 
    552       return (NULL);
    553     }
    554     else if ((sptr = strchr(temps, '%')) != NULL)
    555     {
    556      /*
    557       * Convert "%zone" to "+zone" to match URI form...
    558       */
    559 
    560       *sptr = '+';
    561     }
    562 
    563 #  else
    564     int		i;			/* Looping var */
    565     unsigned	temp;			/* Current value */
    566     const char	*prefix;		/* Prefix for address */
    567 
    568 
    569     prefix = "";
    570     for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++)
    571     {
    572       temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
    573 
    574       snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff);
    575       prefix = ":";
    576       sptr += strlen(sptr);
    577 
    578       temp &= 0xffff;
    579 
    580       if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1])
    581       {
    582         snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp);
    583 	sptr += strlen(sptr);
    584       }
    585     }
    586 
    587     if (i < 4)
    588     {
    589       while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i])
    590 	i ++;
    591 
    592       if (i < 4)
    593       {
    594         snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s:", prefix);
    595 	prefix = ":";
    596 	sptr += strlen(sptr);
    597 
    598 	for (; i < 4; i ++)
    599 	{
    600           temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
    601 
    602           if ((temp & 0xffff0000) ||
    603 	      (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1]))
    604 	  {
    605             snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff);
    606 	    sptr += strlen(sptr);
    607           }
    608 
    609           snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp & 0xffff);
    610 	  sptr += strlen(sptr);
    611 	}
    612       }
    613       else if (sptr == s)
    614       {
    615        /*
    616         * Empty address...
    617 	*/
    618 
    619         strlcpy(temps, "::", sizeof(temps));
    620       }
    621       else
    622       {
    623        /*
    624 	* Empty at end...
    625 	*/
    626 
    627         strlcpy(sptr, "::", sizeof(temps) - (size_t)(sptr - temps));
    628       }
    629     }
    630 #  endif /* HAVE_GETNAMEINFO */
    631 
    632    /*
    633     * Add "[v1." and "]" around IPv6 address to convert to URI form.
    634     */
    635 
    636     snprintf(s, (size_t)slen, "[v1.%s]", temps);
    637   }
    638 #endif /* AF_INET6 */
    639   else
    640     strlcpy(s, "UNKNOWN", (size_t)slen);
    641 
    642   DEBUG_printf(("1httpAddrString: returning \"%s\"...", s));
    643 
    644   return (s);
    645 }
    646 
    647 
    648 /*
    649  * 'httpGetAddress()' - Get the address of the connected peer of a connection.
    650  *
    651  * Returns @code NULL@ if the socket is currently unconnected.
    652  *
    653  * @since CUPS 2.0/OS 10.10@
    654  */
    655 
    656 http_addr_t *				/* O - Connected address or @code NULL@ */
    657 httpGetAddress(http_t *http)		/* I - HTTP connection */
    658 {
    659   if (http)
    660     return (http->hostaddr);
    661   else
    662     return (NULL);
    663 }
    664 
    665 
    666 /*
    667  * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
    668  *                         address records for the specified name.
    669  *
    670  * @deprecated@
    671  */
    672 
    673 struct hostent *			/* O - Host entry */
    674 httpGetHostByName(const char *name)	/* I - Hostname or IP address */
    675 {
    676   const char		*nameptr;	/* Pointer into name */
    677   unsigned		ip[4];		/* IP address components */
    678   _cups_globals_t	*cg = _cupsGlobals();
    679   					/* Pointer to library globals */
    680 
    681 
    682   DEBUG_printf(("httpGetHostByName(name=\"%s\")", name));
    683 
    684  /*
    685   * Avoid lookup delays and configuration problems when connecting
    686   * to the localhost address...
    687   */
    688 
    689   if (!strcmp(name, "localhost"))
    690     name = "127.0.0.1";
    691 
    692  /*
    693   * This function is needed because some operating systems have a
    694   * buggy implementation of gethostbyname() that does not support
    695   * IP addresses.  If the first character of the name string is a
    696   * number, then sscanf() is used to extract the IP components.
    697   * We then pack the components into an IPv4 address manually,
    698   * since the inet_aton() function is deprecated.  We use the
    699   * htonl() macro to get the right byte order for the address.
    700   *
    701   * We also support domain sockets when supported by the underlying
    702   * OS...
    703   */
    704 
    705 #ifdef AF_LOCAL
    706   if (name[0] == '/')
    707   {
    708    /*
    709     * A domain socket address, so make an AF_LOCAL entry and return it...
    710     */
    711 
    712     cg->hostent.h_name      = (char *)name;
    713     cg->hostent.h_aliases   = NULL;
    714     cg->hostent.h_addrtype  = AF_LOCAL;
    715     cg->hostent.h_length    = (int)strlen(name) + 1;
    716     cg->hostent.h_addr_list = cg->ip_ptrs;
    717     cg->ip_ptrs[0]          = (char *)name;
    718     cg->ip_ptrs[1]          = NULL;
    719 
    720     DEBUG_puts("1httpGetHostByName: returning domain socket address...");
    721 
    722     return (&cg->hostent);
    723   }
    724 #endif /* AF_LOCAL */
    725 
    726   for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
    727 
    728   if (!*nameptr)
    729   {
    730    /*
    731     * We have an IPv4 address; break it up and provide the host entry
    732     * to the caller.
    733     */
    734 
    735     if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
    736       return (NULL);			/* Must have 4 numbers */
    737 
    738     if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
    739       return (NULL);			/* Invalid byte ranges! */
    740 
    741     cg->ip_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) |
    742                            (unsigned)ip[2]) << 8) |
    743                          (unsigned)ip[3]));
    744 
    745    /*
    746     * Fill in the host entry and return it...
    747     */
    748 
    749     cg->hostent.h_name      = (char *)name;
    750     cg->hostent.h_aliases   = NULL;
    751     cg->hostent.h_addrtype  = AF_INET;
    752     cg->hostent.h_length    = 4;
    753     cg->hostent.h_addr_list = cg->ip_ptrs;
    754     cg->ip_ptrs[0]          = (char *)&(cg->ip_addr);
    755     cg->ip_ptrs[1]          = NULL;
    756 
    757     DEBUG_puts("1httpGetHostByName: returning IPv4 address...");
    758 
    759     return (&cg->hostent);
    760   }
    761   else
    762   {
    763    /*
    764     * Use the gethostbyname() function to get the IPv4 address for
    765     * the name...
    766     */
    767 
    768     DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)...");
    769 
    770     return (gethostbyname(name));
    771   }
    772 }
    773 
    774 
    775 /*
    776  * 'httpGetHostname()' - Get the FQDN for the connection or local system.
    777  *
    778  * When "http" points to a connected socket, return the hostname or
    779  * address that was used in the call to httpConnect() or httpConnectEncrypt(),
    780  * or the address of the client for the connection from httpAcceptConnection().
    781  * Otherwise, return the FQDN for the local system using both gethostname()
    782  * and gethostbyname() to get the local hostname with domain.
    783  *
    784  * @since CUPS 1.2/macOS 10.5@
    785  */
    786 
    787 const char *				/* O - FQDN for connection or system */
    788 httpGetHostname(http_t *http,		/* I - HTTP connection or NULL */
    789                 char   *s,		/* I - String buffer for name */
    790                 int    slen)		/* I - Size of buffer */
    791 {
    792   if (http)
    793   {
    794     if (!s || slen <= 1)
    795     {
    796       if (http->hostname[0] == '/')
    797 	return ("localhost");
    798       else
    799 	return (http->hostname);
    800     }
    801     else if (http->hostname[0] == '/')
    802       strlcpy(s, "localhost", (size_t)slen);
    803     else
    804       strlcpy(s, http->hostname, (size_t)slen);
    805   }
    806   else
    807   {
    808    /*
    809     * Get the hostname...
    810     */
    811 
    812     if (!s || slen <= 1)
    813       return (NULL);
    814 
    815     if (gethostname(s, (size_t)slen) < 0)
    816       strlcpy(s, "localhost", (size_t)slen);
    817 
    818     if (!strchr(s, '.'))
    819     {
    820 #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
    821      /*
    822       * The hostname is not a FQDN, so use the local hostname from the
    823       * SystemConfiguration framework...
    824       */
    825 
    826       SCDynamicStoreRef	sc = SCDynamicStoreCreate(kCFAllocatorDefault,
    827                                                   CFSTR("libcups"), NULL, NULL);
    828 					/* System configuration data */
    829       CFStringRef	local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL;
    830 					/* Local host name */
    831       char		localStr[1024];	/* Local host name C string */
    832 
    833       if (local && CFStringGetCString(local, localStr, sizeof(localStr),
    834                                       kCFStringEncodingUTF8))
    835       {
    836        /*
    837         * Append ".local." to the hostname we get...
    838 	*/
    839 
    840         snprintf(s, (size_t)slen, "%s.local.", localStr);
    841       }
    842 
    843       if (local)
    844         CFRelease(local);
    845       if (sc)
    846         CFRelease(sc);
    847 
    848 #else
    849      /*
    850       * The hostname is not a FQDN, so look it up...
    851       */
    852 
    853       struct hostent	*host;		/* Host entry to get FQDN */
    854 
    855       if ((host = gethostbyname(s)) != NULL && host->h_name)
    856       {
    857        /*
    858         * Use the resolved hostname...
    859 	*/
    860 
    861 	strlcpy(s, host->h_name, (size_t)slen);
    862       }
    863 #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
    864     }
    865 
    866    /*
    867     * Make sure .local hostnames end with a period...
    868     */
    869 
    870     if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local"))
    871       strlcat(s, ".", (size_t)slen);
    872   }
    873 
    874  /*
    875   * Convert the hostname to lowercase as needed...
    876   */
    877 
    878   if (s[0] != '/')
    879   {
    880     char	*ptr;			/* Pointer into string */
    881 
    882     for (ptr = s; *ptr; ptr ++)
    883       *ptr = (char)_cups_tolower((int)*ptr);
    884   }
    885 
    886  /*
    887   * Return the hostname with as much domain info as we have...
    888   */
    889 
    890   return (s);
    891 }
    892 
    893 
    894 /*
    895  * 'httpResolveHostname()' - Resolve the hostname of the HTTP connection
    896  *                           address.
    897  *
    898  * @since CUPS 2.0/OS 10.10@
    899  */
    900 
    901 const char *				/* O - Resolved hostname or @code NULL@ */
    902 httpResolveHostname(http_t *http,	/* I - HTTP connection */
    903                     char   *buffer,	/* I - Hostname buffer */
    904                     size_t bufsize)	/* I - Size of buffer */
    905 {
    906   if (!http)
    907     return (NULL);
    908 
    909   if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[')
    910   {
    911     char	temp[1024];		/* Temporary string */
    912 
    913     if (httpAddrLookup(http->hostaddr, temp, sizeof(temp)))
    914       strlcpy(http->hostname, temp, sizeof(http->hostname));
    915     else
    916       return (NULL);
    917   }
    918 
    919   if (buffer)
    920   {
    921     if (http->hostname[0] == '/')
    922       strlcpy(buffer, "localhost", bufsize);
    923     else
    924       strlcpy(buffer, http->hostname, bufsize);
    925 
    926     return (buffer);
    927   }
    928   else if (http->hostname[0] == '/')
    929     return ("localhost");
    930   else
    931     return (http->hostname);
    932 }
    933