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