1 /*
2  * HTTP address list routines for CUPS.
3  *
4  * Copyright 2007-2017 by Apple Inc.
5  * Copyright 1997-2007 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 #ifdef HAVE_RESOLV_H
22 #  include <resolv.h>
23 #endif /* HAVE_RESOLV_H */
24 #ifdef HAVE_POLL
25 #  include <poll.h>
26 #endif /* HAVE_POLL */
27 #ifndef WIN32
28 #  include <fcntl.h>
29 #endif /* WIN32 */
30 
31 
32 /*
33  * 'httpAddrConnect()' - Connect to any of the addresses in the list.
34  *
35  * @since CUPS 1.2/macOS 10.5@ @exclude all@
36  */
37 
38 http_addrlist_t *			/* O - Connected address or NULL on failure */
httpAddrConnect(http_addrlist_t * addrlist,int * sock)39 httpAddrConnect(
40     http_addrlist_t *addrlist,		/* I - List of potential addresses */
41     int             *sock)		/* O - Socket */
42 {
43   DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", (void *)addrlist, (void *)sock));
44 
45   return (httpAddrConnect2(addrlist, sock, 30000, NULL));
46 }
47 
48 
49 /*
50  * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a
51  *                        timeout and optional cancel.
52  *
53  * @since CUPS 1.7/macOS 10.9@
54  */
55 
56 http_addrlist_t *			/* O - Connected address or NULL on failure */
httpAddrConnect2(http_addrlist_t * addrlist,int * sock,int msec,int * cancel)57 httpAddrConnect2(
58     http_addrlist_t *addrlist,		/* I - List of potential addresses */
59     int             *sock,		/* O - Socket */
60     int             msec,		/* I - Timeout in milliseconds */
61     int             *cancel)		/* I - Pointer to "cancel" variable */
62 {
63   int			val;		/* Socket option value */
64 #ifndef WIN32
65   int			flags;		/* Socket flags */
66 #endif /* !WIN32 */
67   int			remaining;	/* Remaining timeout */
68   int			i, j,		/* Looping vars */
69 			nfds,		/* Number of file descriptors */
70 			fds[100],	/* Socket file descriptors */
71 			result;		/* Result from select() or poll() */
72   http_addrlist_t	*addrs[100];	/* Addresses */
73 #ifndef HAVE_POLL
74   int			max_fd = -1;	/* Highest file descriptor */
75 #endif /* !HAVE_POLL */
76 #ifdef O_NONBLOCK
77 #  ifdef HAVE_POLL
78   struct pollfd		pfds[100];	/* Polled file descriptors */
79 #  else
80   fd_set		input_set,	/* select() input set */
81 			output_set,	/* select() output set */
82 			error_set;	/* select() error set */
83   struct timeval	timeout;	/* Timeout */
84 #  endif /* HAVE_POLL */
85 #endif /* O_NONBLOCK */
86 #ifdef DEBUG
87   socklen_t		len;		/* Length of value */
88   http_addr_t		peer;		/* Peer address */
89   char			temp[256];	/* Temporary address string */
90 #endif /* DEBUG */
91 
92 
93   DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel));
94 
95   if (!sock)
96   {
97     errno = EINVAL;
98     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
99     return (NULL);
100   }
101 
102   if (cancel && *cancel)
103     return (NULL);
104 
105   if (msec <= 0)
106     msec = INT_MAX;
107 
108  /*
109   * Loop through each address until we connect or run out of addresses...
110   */
111 
112   nfds      = 0;
113   remaining = msec;
114 
115   while (remaining > 0)
116   {
117     if (cancel && *cancel)
118     {
119       while (nfds > 0)
120       {
121         nfds --;
122 	httpAddrClose(NULL, fds[nfds]);
123       }
124 
125       return (NULL);
126     }
127 
128     if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0])))
129     {
130      /*
131       * Create the socket...
132       */
133 
134       DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
135 
136       if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0)
137       {
138        /*
139 	* Don't abort yet, as this could just be an issue with the local
140 	* system not being configured with IPv4/IPv6/domain socket enabled.
141 	*
142 	* Just skip this address...
143 	*/
144 
145         addrlist = addrlist->next;
146 	continue;
147       }
148 
149      /*
150       * Set options...
151       */
152 
153       val = 1;
154       setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
155 
156 #ifdef SO_REUSEPORT
157       val = 1;
158       setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
159 #endif /* SO_REUSEPORT */
160 
161 #ifdef SO_NOSIGPIPE
162       val = 1;
163       setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
164 #endif /* SO_NOSIGPIPE */
165 
166      /*
167       * Using TCP_NODELAY improves responsiveness, especially on systems
168       * with a slow loopback interface...
169       */
170 
171       val = 1;
172       setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
173 
174 #ifdef FD_CLOEXEC
175      /*
176       * Close this socket when starting another process...
177       */
178 
179       fcntl(fds[nfds], F_SETFD, FD_CLOEXEC);
180 #endif /* FD_CLOEXEC */
181 
182 #ifdef O_NONBLOCK
183      /*
184       * Do an asynchronous connect by setting the socket non-blocking...
185       */
186 
187       DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));
188 
189       flags = fcntl(fds[nfds], F_GETFL, 0);
190       fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK);
191 #endif /* O_NONBLOCK */
192 
193      /*
194       * Then connect...
195       */
196 
197       if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr))))
198       {
199 	DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
200 
201 #ifdef O_NONBLOCK
202 	fcntl(fds[nfds], F_SETFL, flags);
203 #endif /* O_NONBLOCK */
204 
205 	*sock = fds[nfds];
206 
207 	while (nfds > 0)
208 	{
209 	  nfds --;
210 	  httpAddrClose(NULL, fds[nfds]);
211 	}
212 
213 	return (addrlist);
214       }
215 
216 #ifdef WIN32
217       if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
218 #else
219       if (errno != EINPROGRESS && errno != EWOULDBLOCK)
220 #endif /* WIN32 */
221       {
222 	DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno)));
223 	httpAddrClose(NULL, fds[nfds]);
224 	addrlist = addrlist->next;
225 	continue;
226       }
227 
228 #ifndef WIN32
229       fcntl(fds[nfds], F_SETFL, flags);
230 #endif /* !WIN32 */
231 
232 #ifndef HAVE_POLL
233       if (fds[nfds] > max_fd)
234 	max_fd = fds[nfds];
235 #endif /* !HAVE_POLL */
236 
237       addrs[nfds] = addrlist;
238       nfds ++;
239       addrlist = addrlist->next;
240     }
241 
242     if (!addrlist && nfds == 0)
243       break;
244 
245    /*
246     * See if we can connect to any of the addresses so far...
247     */
248 
249 #ifdef O_NONBLOCK
250     DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
251 
252     do
253     {
254       if (cancel && *cancel)
255       {
256        /*
257 	* Close this socket and return...
258 	*/
259 
260 	DEBUG_puts("1httpAddrConnect2: Canceled connect()");
261 
262 	while (nfds > 0)
263 	{
264 	  nfds --;
265 	  httpAddrClose(NULL, fds[nfds]);
266 	}
267 
268 	*sock = -1;
269 
270 	return (NULL);
271       }
272 
273 #  ifdef HAVE_POLL
274       for (i = 0; i < nfds; i ++)
275       {
276 	pfds[i].fd     = fds[i];
277 	pfds[i].events = POLLIN | POLLOUT;
278       }
279 
280       result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining);
281 
282       DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno));
283 
284 #  else
285       FD_ZERO(&input_set);
286       for (i = 0; i < nfds; i ++)
287 	FD_SET(fds[i], &input_set);
288       output_set = input_set;
289       error_set  = input_set;
290 
291       timeout.tv_sec  = 0;
292       timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000;
293 
294       result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout);
295 
296       DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno));
297 #  endif /* HAVE_POLL */
298     }
299 #  ifdef WIN32
300     while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
301 #  else
302     while (result < 0 && (errno == EINTR || errno == EAGAIN));
303 #  endif /* WIN32 */
304 
305     if (result > 0)
306     {
307       http_addrlist_t *connaddr = NULL;	/* Connected address, if any */
308 
309       for (i = 0; i < nfds; i ++)
310       {
311 #  ifdef HAVE_POLL
312 	DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents));
313 	if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP)))
314 #  else
315 	if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set))
316 #  endif /* HAVE_POLL */
317 	{
318 	  *sock    = fds[i];
319 	  connaddr = addrs[i];
320 
321 #  ifdef DEBUG
322 	  len   = sizeof(peer);
323 	  if (!getpeername(fds[i], (struct sockaddr *)&peer, &len))
324 	    DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer)));
325 #  endif /* DEBUG */
326 
327           break;
328 	}
329 #  ifdef HAVE_POLL
330 	else if (pfds[i].revents & (POLLERR | POLLHUP))
331 #  else
332 	else if (FD_ISSET(fds[i], &error_set))
333 #  endif /* HAVE_POLL */
334         {
335          /*
336           * Error on socket, remove from the "pool"...
337           */
338 
339 	  httpAddrClose(NULL, fds[i]);
340           nfds --;
341           if (i < nfds)
342           {
343             memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0])));
344             memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0])));
345           }
346           i --;
347         }
348       }
349 
350       if (connaddr)
351       {
352        /*
353         * Connected on one address, close all of the other sockets we have so
354         * far and return...
355         */
356 
357         for (j = 0; j < i; j ++)
358           httpAddrClose(NULL, fds[j]);
359 
360         for (j ++; j < nfds; j ++)
361           httpAddrClose(NULL, fds[j]);
362 
363         return (connaddr);
364       }
365     }
366 #endif /* O_NONBLOCK */
367 
368     if (addrlist)
369       remaining -= 100;
370     else
371       remaining -= 250;
372   }
373 
374   while (nfds > 0)
375   {
376     nfds --;
377     httpAddrClose(NULL, fds[nfds]);
378   }
379 
380 #ifdef WIN32
381   _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
382 #else
383   _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
384 #endif /* WIN32 */
385 
386   return (NULL);
387 }
388 
389 
390 /*
391  * 'httpAddrCopyList()' - Copy an address list.
392  *
393  * @since CUPS 1.7/macOS 10.9@
394  */
395 
396 http_addrlist_t	*			/* O - New address list or @code NULL@ on error */
httpAddrCopyList(http_addrlist_t * src)397 httpAddrCopyList(
398     http_addrlist_t *src)		/* I - Source address list */
399 {
400   http_addrlist_t	*dst = NULL,	/* First list entry */
401 			*prev = NULL,	/* Previous list entry */
402 			*current = NULL;/* Current list entry */
403 
404 
405   while (src)
406   {
407     if ((current = malloc(sizeof(http_addrlist_t))) == NULL)
408     {
409       current = dst;
410 
411       while (current)
412       {
413         prev    = current;
414         current = current->next;
415 
416         free(prev);
417       }
418 
419       return (NULL);
420     }
421 
422     memcpy(current, src, sizeof(http_addrlist_t));
423 
424     current->next = NULL;
425 
426     if (prev)
427       prev->next = current;
428     else
429       dst = current;
430 
431     prev = current;
432     src  = src->next;
433   }
434 
435   return (dst);
436 }
437 
438 
439 /*
440  * 'httpAddrFreeList()' - Free an address list.
441  *
442  * @since CUPS 1.2/macOS 10.5@
443  */
444 
445 void
httpAddrFreeList(http_addrlist_t * addrlist)446 httpAddrFreeList(
447     http_addrlist_t *addrlist)		/* I - Address list to free */
448 {
449   http_addrlist_t	*next;		/* Next address in list */
450 
451 
452  /*
453   * Free each address in the list...
454   */
455 
456   while (addrlist)
457   {
458     next = addrlist->next;
459 
460     free(addrlist);
461 
462     addrlist = next;
463   }
464 }
465 
466 
467 /*
468  * 'httpAddrGetList()' - Get a list of addresses for a hostname.
469  *
470  * @since CUPS 1.2/macOS 10.5@
471  */
472 
473 http_addrlist_t	*			/* O - List of addresses or NULL */
httpAddrGetList(const char * hostname,int family,const char * service)474 httpAddrGetList(const char *hostname,	/* I - Hostname, IP address, or NULL for passive listen address */
475                 int        family,	/* I - Address family or AF_UNSPEC */
476 		const char *service)	/* I - Service name or port number */
477 {
478   http_addrlist_t	*first,		/* First address in list */
479 			*addr,		/* Current address in list */
480 			*temp;		/* New address */
481   _cups_globals_t	*cg = _cupsGlobals();
482 					/* Global data */
483 
484 
485 #ifdef DEBUG
486   _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
487                      "service=\"%s\")\n",
488 		     hostname ? hostname : "(nil)",
489 		     family == AF_UNSPEC ? "UNSPEC" :
490 #  ifdef AF_LOCAL
491 	                 family == AF_LOCAL ? "LOCAL" :
492 #  endif /* AF_LOCAL */
493 #  ifdef AF_INET6
494 	                 family == AF_INET6 ? "INET6" :
495 #  endif /* AF_INET6 */
496 	                 family == AF_INET ? "INET" : "???", service);
497 #endif /* DEBUG */
498 
499 #ifdef HAVE_RES_INIT
500  /*
501   * STR #2920: Initialize resolver after failure in cups-polld
502   *
503   * If the previous lookup failed, re-initialize the resolver to prevent
504   * temporary network errors from persisting.  This *should* be handled by
505   * the resolver libraries, but apparently the glibc folks do not agree.
506   *
507   * We set a flag at the end of this function if we encounter an error that
508   * requires reinitialization of the resolver functions.  We then call
509   * res_init() if the flag is set on the next call here or in httpAddrLookup().
510   */
511 
512   if (cg->need_res_init)
513   {
514     res_init();
515 
516     cg->need_res_init = 0;
517   }
518 #endif /* HAVE_RES_INIT */
519 
520  /*
521   * Lookup the address the best way we can...
522   */
523 
524   first = addr = NULL;
525 
526 #ifdef AF_LOCAL
527   if (hostname && hostname[0] == '/')
528   {
529    /*
530     * Domain socket address...
531     */
532 
533     if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
534     {
535       addr = first;
536       first->addr.un.sun_family = AF_LOCAL;
537       strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
538     }
539   }
540   else
541 #endif /* AF_LOCAL */
542   if (!hostname || _cups_strcasecmp(hostname, "localhost"))
543   {
544 #ifdef HAVE_GETADDRINFO
545     struct addrinfo	hints,		/* Address lookup hints */
546 			*results,	/* Address lookup results */
547 			*current;	/* Current result */
548     char		ipv6[64],	/* IPv6 address */
549 			*ipv6zone;	/* Pointer to zone separator */
550     int			ipv6len;	/* Length of IPv6 address */
551     int			error;		/* getaddrinfo() error */
552 
553 
554    /*
555     * Lookup the address as needed...
556     */
557 
558     memset(&hints, 0, sizeof(hints));
559     hints.ai_family   = family;
560     hints.ai_flags    = hostname ? 0 : AI_PASSIVE;
561     hints.ai_socktype = SOCK_STREAM;
562 
563     if (hostname && *hostname == '[')
564     {
565      /*
566       * Remove brackets from numeric IPv6 address...
567       */
568 
569       if (!strncmp(hostname, "[v1.", 4))
570       {
571        /*
572         * Copy the newer address format which supports link-local addresses...
573 	*/
574 
575 	strlcpy(ipv6, hostname + 4, sizeof(ipv6));
576 	if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
577 	{
578           ipv6[ipv6len] = '\0';
579 	  hostname      = ipv6;
580 
581          /*
582 	  * Convert "+zone" in address to "%zone"...
583 	  */
584 
585           if ((ipv6zone = strrchr(ipv6, '+')) != NULL)
586 	    *ipv6zone = '%';
587 	}
588       }
589       else
590       {
591        /*
592         * Copy the regular non-link-local IPv6 address...
593 	*/
594 
595 	strlcpy(ipv6, hostname + 1, sizeof(ipv6));
596 	if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
597 	{
598           ipv6[ipv6len] = '\0';
599 	  hostname      = ipv6;
600 	}
601       }
602     }
603 
604     if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
605     {
606      /*
607       * Copy the results to our own address list structure...
608       */
609 
610       for (current = results; current; current = current->ai_next)
611         if (current->ai_family == AF_INET || current->ai_family == AF_INET6)
612 	{
613 	 /*
614           * Copy the address over...
615 	  */
616 
617 	  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
618 	  if (!temp)
619 	  {
620 	    httpAddrFreeList(first);
621 	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
622 	    return (NULL);
623 	  }
624 
625           if (current->ai_family == AF_INET6)
626 	    memcpy(&(temp->addr.ipv6), current->ai_addr,
627 	           sizeof(temp->addr.ipv6));
628 	  else
629 	    memcpy(&(temp->addr.ipv4), current->ai_addr,
630 	           sizeof(temp->addr.ipv4));
631 
632          /*
633 	  * Append the address to the list...
634 	  */
635 
636 	  if (!first)
637 	    first = temp;
638 
639 	  if (addr)
640 	    addr->next = temp;
641 
642 	  addr = temp;
643 	}
644 
645      /*
646       * Free the results from getaddrinfo()...
647       */
648 
649       freeaddrinfo(results);
650     }
651     else
652     {
653       if (error == EAI_FAIL)
654         cg->need_res_init = 1;
655 
656       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
657     }
658 
659 #else
660     if (hostname)
661     {
662       int		i;		/* Looping vars */
663       unsigned		ip[4];		/* IPv4 address components */
664       const char	*ptr;		/* Pointer into hostname */
665       struct hostent	*host;		/* Result of lookup */
666       struct servent	*port;		/* Port number for service */
667       int		portnum;	/* Port number */
668 
669 
670      /*
671       * Lookup the service...
672       */
673 
674       if (!service)
675 	portnum = 0;
676       else if (isdigit(*service & 255))
677 	portnum = atoi(service);
678       else if ((port = getservbyname(service, NULL)) != NULL)
679 	portnum = ntohs(port->s_port);
680       else if (!strcmp(service, "http"))
681         portnum = 80;
682       else if (!strcmp(service, "https"))
683         portnum = 443;
684       else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
685         portnum = 631;
686       else if (!strcmp(service, "lpd"))
687         portnum = 515;
688       else if (!strcmp(service, "socket"))
689         portnum = 9100;
690       else
691 	return (NULL);
692 
693      /*
694       * This code is needed because some operating systems have a
695       * buggy implementation of gethostbyname() that does not support
696       * IPv4 addresses.  If the hostname string is an IPv4 address, then
697       * sscanf() is used to extract the IPv4 components.  We then pack
698       * the components into an IPv4 address manually, since the
699       * inet_aton() function is deprecated.  We use the htonl() macro
700       * to get the right byte order for the address.
701       */
702 
703       for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++);
704 
705       if (!*ptr)
706       {
707        /*
708 	* We have an IPv4 address; break it up and create an IPv4 address...
709 	*/
710 
711 	if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 &&
712             ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255)
713 	{
714 	  first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
715 	  if (!first)
716 	    return (NULL);
717 
718           first->addr.ipv4.sin_family = AF_INET;
719           first->addr.ipv4.sin_addr.s_addr = htonl((((((((unsigned)ip[0] << 8) |
720 	                                               (unsigned)ip[1]) << 8) |
721 						     (unsigned)ip[2]) << 8) |
722 						   (unsigned)ip[3]));
723           first->addr.ipv4.sin_port = htons(portnum);
724 	}
725       }
726       else if ((host = gethostbyname(hostname)) != NULL &&
727 #  ifdef AF_INET6
728                (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6))
729 #  else
730                host->h_addrtype == AF_INET)
731 #  endif /* AF_INET6 */
732       {
733 	for (i = 0; host->h_addr_list[i]; i ++)
734 	{
735 	 /*
736           * Copy the address over...
737 	  */
738 
739 	  temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
740 	  if (!temp)
741 	  {
742 	    httpAddrFreeList(first);
743 	    return (NULL);
744 	  }
745 
746 #  ifdef AF_INET6
747           if (host->h_addrtype == AF_INET6)
748 	  {
749             temp->addr.ipv6.sin6_family = AF_INET6;
750 	    memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i],
751 	           sizeof(temp->addr.ipv6));
752             temp->addr.ipv6.sin6_port = htons(portnum);
753 	  }
754 	  else
755 #  endif /* AF_INET6 */
756 	  {
757             temp->addr.ipv4.sin_family = AF_INET;
758 	    memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i],
759 	           sizeof(temp->addr.ipv4));
760             temp->addr.ipv4.sin_port = htons(portnum);
761           }
762 
763 	 /*
764 	  * Append the address to the list...
765 	  */
766 
767 	  if (!first)
768 	    first = temp;
769 
770 	  if (addr)
771 	    addr->next = temp;
772 
773 	  addr = temp;
774 	}
775       }
776       else
777       {
778         if (h_errno == NO_RECOVERY)
779           cg->need_res_init = 1;
780 
781 	_cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0);
782       }
783     }
784 #endif /* HAVE_GETADDRINFO */
785   }
786 
787  /*
788   * Detect some common errors and handle them sanely...
789   */
790 
791   if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost")))
792   {
793     struct servent	*port;		/* Port number for service */
794     int			portnum;	/* Port number */
795 
796 
797    /*
798     * Lookup the service...
799     */
800 
801     if (!service)
802       portnum = 0;
803     else if (isdigit(*service & 255))
804       portnum = atoi(service);
805     else if ((port = getservbyname(service, NULL)) != NULL)
806       portnum = ntohs(port->s_port);
807     else if (!strcmp(service, "http"))
808       portnum = 80;
809     else if (!strcmp(service, "https"))
810       portnum = 443;
811     else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
812       portnum = 631;
813     else if (!strcmp(service, "lpd"))
814       portnum = 515;
815     else if (!strcmp(service, "socket"))
816       portnum = 9100;
817     else
818     {
819       httpAddrFreeList(first);
820 
821       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1);
822       return (NULL);
823     }
824 
825     if (hostname && !_cups_strcasecmp(hostname, "localhost"))
826     {
827      /*
828       * Unfortunately, some users ignore all of the warnings in the
829       * /etc/hosts file and delete "localhost" from it. If we get here
830       * then we were unable to resolve the name, so use the IPv6 and/or
831       * IPv4 loopback interface addresses...
832       */
833 
834 #ifdef AF_INET6
835       if (family != AF_INET)
836       {
837        /*
838         * Add [::1] to the address list...
839 	*/
840 
841 	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
842 	if (!temp)
843 	{
844 	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
845 	  httpAddrFreeList(first);
846 	  return (NULL);
847 	}
848 
849         temp->addr.ipv6.sin6_family            = AF_INET6;
850 	temp->addr.ipv6.sin6_port              = htons(portnum);
851 #  ifdef WIN32
852 	temp->addr.ipv6.sin6_addr.u.Byte[15]   = 1;
853 #  else
854 	temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
855 #  endif /* WIN32 */
856 
857         if (!first)
858           first = temp;
859 
860         addr = temp;
861       }
862 
863       if (family != AF_INET6)
864 #endif /* AF_INET6 */
865       {
866        /*
867         * Add 127.0.0.1 to the address list...
868 	*/
869 
870 	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
871 	if (!temp)
872 	{
873 	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
874 	  httpAddrFreeList(first);
875 	  return (NULL);
876 	}
877 
878         temp->addr.ipv4.sin_family      = AF_INET;
879 	temp->addr.ipv4.sin_port        = htons(portnum);
880 	temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001);
881 
882         if (!first)
883           first = temp;
884 
885         if (addr)
886 	  addr->next = temp;
887       }
888     }
889     else if (!hostname)
890     {
891      /*
892       * Provide one or more passive listening addresses...
893       */
894 
895 #ifdef AF_INET6
896       if (family != AF_INET)
897       {
898        /*
899         * Add [::] to the address list...
900 	*/
901 
902 	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
903 	if (!temp)
904 	{
905 	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
906 	  httpAddrFreeList(first);
907 	  return (NULL);
908 	}
909 
910         temp->addr.ipv6.sin6_family = AF_INET6;
911 	temp->addr.ipv6.sin6_port   = htons(portnum);
912 
913         if (!first)
914           first = temp;
915 
916         addr = temp;
917       }
918 
919       if (family != AF_INET6)
920 #endif /* AF_INET6 */
921       {
922        /*
923         * Add 0.0.0.0 to the address list...
924 	*/
925 
926 	temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
927 	if (!temp)
928 	{
929 	  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
930 	  httpAddrFreeList(first);
931 	  return (NULL);
932 	}
933 
934         temp->addr.ipv4.sin_family = AF_INET;
935 	temp->addr.ipv4.sin_port   = htons(portnum);
936 
937         if (!first)
938           first = temp;
939 
940         if (addr)
941 	  addr->next = temp;
942       }
943     }
944   }
945 
946  /*
947   * Return the address list...
948   */
949 
950   return (first);
951 }
952