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 httpAddrConnect2@ and the
     62  * listen address for sockets created with @link httpAddrListen@.  This function
     63  * ensures 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  * For connections created with @link httpConnect2@, the address is for the
    652  * server.  For connections created with @link httpAccept@, the address is for
    653  * the client.
    654  *
    655  * Returns @code NULL@ if the socket is currently unconnected.
    656  *
    657  * @since CUPS 2.0/OS 10.10@
    658  */
    659 
    660 http_addr_t *				/* O - Connected address or @code NULL@ */
    661 httpGetAddress(http_t *http)		/* I - HTTP connection */
    662 {
    663   if (http)
    664     return (http->hostaddr);
    665   else
    666     return (NULL);
    667 }
    668 
    669 
    670 /*
    671  * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
    672  *                         address records for the specified name.
    673  *
    674  * @deprecated@ @exclude all@
    675  */
    676 
    677 struct hostent *			/* O - Host entry */
    678 httpGetHostByName(const char *name)	/* I - Hostname or IP address */
    679 {
    680   const char		*nameptr;	/* Pointer into name */
    681   unsigned		ip[4];		/* IP address components */
    682   _cups_globals_t	*cg = _cupsGlobals();
    683   					/* Pointer to library globals */
    684 
    685 
    686   DEBUG_printf(("httpGetHostByName(name=\"%s\")", name));
    687 
    688  /*
    689   * Avoid lookup delays and configuration problems when connecting
    690   * to the localhost address...
    691   */
    692 
    693   if (!strcmp(name, "localhost"))
    694     name = "127.0.0.1";
    695 
    696  /*
    697   * This function is needed because some operating systems have a
    698   * buggy implementation of gethostbyname() that does not support
    699   * IP addresses.  If the first character of the name string is a
    700   * number, then sscanf() is used to extract the IP components.
    701   * We then pack the components into an IPv4 address manually,
    702   * since the inet_aton() function is deprecated.  We use the
    703   * htonl() macro to get the right byte order for the address.
    704   *
    705   * We also support domain sockets when supported by the underlying
    706   * OS...
    707   */
    708 
    709 #ifdef AF_LOCAL
    710   if (name[0] == '/')
    711   {
    712    /*
    713     * A domain socket address, so make an AF_LOCAL entry and return it...
    714     */
    715 
    716     cg->hostent.h_name      = (char *)name;
    717     cg->hostent.h_aliases   = NULL;
    718     cg->hostent.h_addrtype  = AF_LOCAL;
    719     cg->hostent.h_length    = (int)strlen(name) + 1;
    720     cg->hostent.h_addr_list = cg->ip_ptrs;
    721     cg->ip_ptrs[0]          = (char *)name;
    722     cg->ip_ptrs[1]          = NULL;
    723 
    724     DEBUG_puts("1httpGetHostByName: returning domain socket address...");
    725 
    726     return (&cg->hostent);
    727   }
    728 #endif /* AF_LOCAL */
    729 
    730   for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
    731 
    732   if (!*nameptr)
    733   {
    734    /*
    735     * We have an IPv4 address; break it up and provide the host entry
    736     * to the caller.
    737     */
    738 
    739     if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
    740       return (NULL);			/* Must have 4 numbers */
    741 
    742     if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
    743       return (NULL);			/* Invalid byte ranges! */
    744 
    745     cg->ip_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) |
    746                            (unsigned)ip[2]) << 8) |
    747                          (unsigned)ip[3]));
    748 
    749    /*
    750     * Fill in the host entry and return it...
    751     */
    752 
    753     cg->hostent.h_name      = (char *)name;
    754     cg->hostent.h_aliases   = NULL;
    755     cg->hostent.h_addrtype  = AF_INET;
    756     cg->hostent.h_length    = 4;
    757     cg->hostent.h_addr_list = cg->ip_ptrs;
    758     cg->ip_ptrs[0]          = (char *)&(cg->ip_addr);
    759     cg->ip_ptrs[1]          = NULL;
    760 
    761     DEBUG_puts("1httpGetHostByName: returning IPv4 address...");
    762 
    763     return (&cg->hostent);
    764   }
    765   else
    766   {
    767    /*
    768     * Use the gethostbyname() function to get the IPv4 address for
    769     * the name...
    770     */
    771 
    772     DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)...");
    773 
    774     return (gethostbyname(name));
    775   }
    776 }
    777 
    778 
    779 /*
    780  * 'httpGetHostname()' - Get the FQDN for the connection or local system.
    781  *
    782  * When "http" points to a connected socket, return the hostname or
    783  * address that was used in the call to httpConnect() or httpConnectEncrypt(),
    784  * or the address of the client for the connection from httpAcceptConnection().
    785  * Otherwise, return the FQDN for the local system using both gethostname()
    786  * and gethostbyname() to get the local hostname with domain.
    787  *
    788  * @since CUPS 1.2/macOS 10.5@
    789  */
    790 
    791 const char *				/* O - FQDN for connection or system */
    792 httpGetHostname(http_t *http,		/* I - HTTP connection or NULL */
    793                 char   *s,		/* I - String buffer for name */
    794                 int    slen)		/* I - Size of buffer */
    795 {
    796   if (http)
    797   {
    798     if (!s || slen <= 1)
    799     {
    800       if (http->hostname[0] == '/')
    801 	return ("localhost");
    802       else
    803 	return (http->hostname);
    804     }
    805     else if (http->hostname[0] == '/')
    806       strlcpy(s, "localhost", (size_t)slen);
    807     else
    808       strlcpy(s, http->hostname, (size_t)slen);
    809   }
    810   else
    811   {
    812    /*
    813     * Get the hostname...
    814     */
    815 
    816     if (!s || slen <= 1)
    817       return (NULL);
    818 
    819     if (gethostname(s, (size_t)slen) < 0)
    820       strlcpy(s, "localhost", (size_t)slen);
    821 
    822     if (!strchr(s, '.'))
    823     {
    824 #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
    825      /*
    826       * The hostname is not a FQDN, so use the local hostname from the
    827       * SystemConfiguration framework...
    828       */
    829 
    830       SCDynamicStoreRef	sc = SCDynamicStoreCreate(kCFAllocatorDefault,
    831                                                   CFSTR("libcups"), NULL, NULL);
    832 					/* System configuration data */
    833       CFStringRef	local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL;
    834 					/* Local host name */
    835       char		localStr[1024];	/* Local host name C string */
    836 
    837       if (local && CFStringGetCString(local, localStr, sizeof(localStr),
    838                                       kCFStringEncodingUTF8))
    839       {
    840        /*
    841         * Append ".local." to the hostname we get...
    842 	*/
    843 
    844         snprintf(s, (size_t)slen, "%s.local.", localStr);
    845       }
    846 
    847       if (local)
    848         CFRelease(local);
    849       if (sc)
    850         CFRelease(sc);
    851 
    852 #else
    853      /*
    854       * The hostname is not a FQDN, so look it up...
    855       */
    856 
    857       struct hostent	*host;		/* Host entry to get FQDN */
    858 
    859       if ((host = gethostbyname(s)) != NULL && host->h_name)
    860       {
    861        /*
    862         * Use the resolved hostname...
    863 	*/
    864 
    865 	strlcpy(s, host->h_name, (size_t)slen);
    866       }
    867 #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
    868     }
    869 
    870    /*
    871     * Make sure .local hostnames end with a period...
    872     */
    873 
    874     if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local"))
    875       strlcat(s, ".", (size_t)slen);
    876   }
    877 
    878  /*
    879   * Convert the hostname to lowercase as needed...
    880   */
    881 
    882   if (s[0] != '/')
    883   {
    884     char	*ptr;			/* Pointer into string */
    885 
    886     for (ptr = s; *ptr; ptr ++)
    887       *ptr = (char)_cups_tolower((int)*ptr);
    888   }
    889 
    890  /*
    891   * Return the hostname with as much domain info as we have...
    892   */
    893 
    894   return (s);
    895 }
    896 
    897 
    898 /*
    899  * 'httpResolveHostname()' - Resolve the hostname of the HTTP connection
    900  *                           address.
    901  *
    902  * @since CUPS 2.0/OS 10.10@
    903  */
    904 
    905 const char *				/* O - Resolved hostname or @code NULL@ */
    906 httpResolveHostname(http_t *http,	/* I - HTTP connection */
    907                     char   *buffer,	/* I - Hostname buffer */
    908                     size_t bufsize)	/* I - Size of buffer */
    909 {
    910   if (!http)
    911     return (NULL);
    912 
    913   if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[')
    914   {
    915     char	temp[1024];		/* Temporary string */
    916 
    917     if (httpAddrLookup(http->hostaddr, temp, sizeof(temp)))
    918       strlcpy(http->hostname, temp, sizeof(http->hostname));
    919     else
    920       return (NULL);
    921   }
    922 
    923   if (buffer)
    924   {
    925     if (http->hostname[0] == '/')
    926       strlcpy(buffer, "localhost", bufsize);
    927     else
    928       strlcpy(buffer, http->hostname, bufsize);
    929 
    930     return (buffer);
    931   }
    932   else if (http->hostname[0] == '/')
    933     return ("localhost");
    934   else
    935     return (http->hostname);
    936 }
    937