]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/http-addr.c
Fix property on test file.
[thirdparty/cups.git] / cups / http-addr.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: http-addr.c 7910 2008-09-06 00:25:17Z mike $"
ef416fc2 3 *
71e16022 4 * HTTP address routines for CUPS.
ef416fc2 5 *
f3c17241 6 * Copyright 2007-2012 by Apple Inc.
ecdc0628 7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * Contents:
16 *
17 * httpAddrAny() - Check for the "any" address.
18 * httpAddrEqual() - Compare two addresses.
19 * httpAddrLocalhost() - Check for the local loopback address.
20 * httpAddrLookup() - Lookup the hostname associated with the address.
1ff0402e 21 * _httpAddrPort() - Get the port number associated with an address.
22c9029b 22 * _httpAddrSetPort() - Set the port number associated with an address.
ef416fc2 23 * httpAddrString() - Convert an IP address to a dotted string.
24 * httpGetHostByName() - Lookup a hostname or IP address, and return
25 * address records for the specified name.
26 * httpGetHostname() - Get the FQDN for the local system.
27 */
28
29/*
30 * Include necessary headers...
31 */
32
71e16022 33#include "cups-private.h"
49d87452
MS
34#ifdef HAVE_RESOLV_H
35# include <resolv.h>
36#endif /* HAVE_RESOLV_H */
a29fd7dd 37#ifdef __APPLE__
1106b00e 38# include <CoreFoundation/CoreFoundation.h>
1106b00e 39# include <SystemConfiguration/SystemConfiguration.h>
a29fd7dd 40#endif /* __APPLE__ */
ef416fc2 41
42
43/*
44 * 'httpAddrAny()' - Check for the "any" address.
45 *
f3c17241 46 * @since CUPS 1.2/OS X 10.5@
ef416fc2 47 */
48
49int /* O - 1 if "any", 0 otherwise */
50httpAddrAny(const http_addr_t *addr) /* I - Address to check */
51{
89d46774 52 if (!addr)
53 return (0);
54
ef416fc2 55#ifdef AF_INET6
56 if (addr->addr.sa_family == AF_INET6 &&
57 IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
58 return (1);
59#endif /* AF_INET6 */
60
61 if (addr->addr.sa_family == AF_INET &&
62 ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
63 return (1);
64
65 return (0);
66}
67
68
69/*
70 * 'httpAddrEqual()' - Compare two addresses.
71 *
f3c17241 72 * @since CUPS 1.2/OS X 10.5@
ef416fc2 73 */
74
ecdc0628 75int /* O - 1 if equal, 0 if not */
ef416fc2 76httpAddrEqual(const http_addr_t *addr1, /* I - First address */
77 const http_addr_t *addr2) /* I - Second address */
78{
89d46774 79 if (!addr1 && !addr2)
80 return (1);
81
82 if (!addr1 || !addr2)
83 return (0);
84
ef416fc2 85 if (addr1->addr.sa_family != addr2->addr.sa_family)
86 return (0);
87
88#ifdef AF_LOCAL
89 if (addr1->addr.sa_family == AF_LOCAL)
90 return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
91#endif /* AF_LOCAL */
92
93#ifdef AF_INET6
94 if (addr1->addr.sa_family == AF_INET6)
95 return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16));
96#endif /* AF_INET6 */
97
98 return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
99}
100
101
102/*
103 * 'httpAddrLength()' - Return the length of the address in bytes.
104 *
f3c17241 105 * @since CUPS 1.2/OS X 10.5@
ef416fc2 106 */
107
108int /* O - Length in bytes */
109httpAddrLength(const http_addr_t *addr) /* I - Address */
110{
89d46774 111 if (!addr)
112 return (0);
113
ef416fc2 114#ifdef AF_INET6
115 if (addr->addr.sa_family == AF_INET6)
116 return (sizeof(addr->ipv6));
117 else
118#endif /* AF_INET6 */
119#ifdef AF_LOCAL
120 if (addr->addr.sa_family == AF_LOCAL)
121 return (offsetof(struct sockaddr_un, sun_path) +
122 strlen(addr->un.sun_path) + 1);
123 else
124#endif /* AF_LOCAL */
125 if (addr->addr.sa_family == AF_INET)
126 return (sizeof(addr->ipv4));
127 else
128 return (0);
129
130}
131
132
133/*
134 * 'httpAddrLocalhost()' - Check for the local loopback address.
135 *
f3c17241 136 * @since CUPS 1.2/OS X 10.5@
ef416fc2 137 */
138
139int /* O - 1 if local host, 0 otherwise */
140httpAddrLocalhost(
141 const http_addr_t *addr) /* I - Address to check */
142{
89d46774 143 if (!addr)
144 return (1);
145
ef416fc2 146#ifdef AF_INET6
147 if (addr->addr.sa_family == AF_INET6 &&
fa73b229 148 IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
ef416fc2 149 return (1);
150#endif /* AF_INET6 */
151
152#ifdef AF_LOCAL
153 if (addr->addr.sa_family == AF_LOCAL)
154 return (1);
155#endif /* AF_LOCAL */
156
157 if (addr->addr.sa_family == AF_INET &&
e07d4801 158 (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000)
ef416fc2 159 return (1);
160
161 return (0);
162}
163
164
ef416fc2 165/*
166 * 'httpAddrLookup()' - Lookup the hostname associated with the address.
167 *
f3c17241 168 * @since CUPS 1.2/OS X 10.5@
ef416fc2 169 */
170
ecdc0628 171char * /* O - Host name */
172httpAddrLookup(
173 const http_addr_t *addr, /* I - Address to lookup */
174 char *name, /* I - Host name buffer */
175 int namelen) /* I - Size of name buffer */
ef416fc2 176{
49d87452
MS
177 _cups_globals_t *cg = _cupsGlobals();
178 /* Global data */
179
180
e07d4801
MS
181 DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", addr, name,
182 namelen));
ef416fc2 183
184 /*
185 * Range check input...
186 */
187
188 if (!addr || !name || namelen <= 2)
189 {
190 if (name && namelen >= 1)
191 *name = '\0';
192
193 return (NULL);
194 }
195
196#ifdef AF_LOCAL
197 if (addr->addr.sa_family == AF_LOCAL)
49d87452 198 {
ef416fc2 199 strlcpy(name, addr->un.sun_path, namelen);
49d87452
MS
200 return (name);
201 }
ef416fc2 202#endif /* AF_LOCAL */
49d87452 203
d2354e63
MS
204 /*
205 * Optimize lookups for localhost/loopback addresses...
206 */
207
208 if (httpAddrLocalhost(addr))
209 {
210 strlcpy(name, "localhost", namelen);
211 return (name);
212 }
213
49d87452
MS
214#ifdef HAVE_RES_INIT
215 /*
216 * STR #2920: Initialize resolver after failure in cups-polld
217 *
218 * If the previous lookup failed, re-initialize the resolver to prevent
219 * temporary network errors from persisting. This *should* be handled by
220 * the resolver libraries, but apparently the glibc folks do not agree.
221 *
222 * We set a flag at the end of this function if we encounter an error that
223 * requires reinitialization of the resolver functions. We then call
224 * res_init() if the flag is set on the next call here or in httpAddrLookup().
225 */
226
227 if (cg->need_res_init)
228 {
229 res_init();
230
231 cg->need_res_init = 0;
232 }
233#endif /* HAVE_RES_INIT */
234
ef416fc2 235#ifdef HAVE_GETNAMEINFO
236 {
db1f069b
MS
237 /*
238 * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN
239 *
240 * FWIW, I think this is really a bug in the implementation of
241 * getnameinfo(), but falling back on httpAddrString() is easy to
242 * do...
243 */
ef416fc2 244
49d87452
MS
245 int error = getnameinfo(&addr->addr, httpAddrLength(addr), name, namelen,
246 NULL, 0, 0);
247
248 if (error)
249 {
250 if (error == EAI_FAIL)
251 cg->need_res_init = 1;
252
db1f069b 253 return (httpAddrString(addr, name, namelen));
49d87452 254 }
ef416fc2 255 }
256#else
257 {
258 struct hostent *host; /* Host from name service */
259
260
261# ifdef AF_INET6
262 if (addr->addr.sa_family == AF_INET6)
3dd9c340 263 host = gethostbyaddr((char *)&(addr->ipv6.sin6_addr),
ef416fc2 264 sizeof(struct in_addr), AF_INET6);
265 else
266# endif /* AF_INET6 */
3dd9c340 267 host = gethostbyaddr((char *)&(addr->ipv4.sin_addr),
ef416fc2 268 sizeof(struct in_addr), AF_INET);
269
270 if (host == NULL)
271 {
272 /*
273 * No hostname, so return the raw address...
274 */
275
49d87452
MS
276 if (h_errno == NO_RECOVERY)
277 cg->need_res_init = 1;
278
279 return (httpAddrString(addr, name, namelen));
ef416fc2 280 }
281
282 strlcpy(name, host->h_name, namelen);
283 }
284#endif /* HAVE_GETNAMEINFO */
285
e07d4801
MS
286 DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name));
287
ef416fc2 288 return (name);
289}
290
291
1ff0402e
MS
292/*
293 * '_httpAddrPort()' - Get the port number associated with an address.
294 */
295
296int /* O - Port number */
297_httpAddrPort(http_addr_t *addr) /* I - Address */
298{
5f64df29
MS
299 if (!addr)
300 return (ippPort());
1ff0402e 301#ifdef AF_INET6
5f64df29 302 else if (addr->addr.sa_family == AF_INET6)
1ff0402e 303 return (ntohs(addr->ipv6.sin6_port));
1ff0402e 304#endif /* AF_INET6 */
5f64df29 305 else if (addr->addr.sa_family == AF_INET)
1ff0402e
MS
306 return (ntohs(addr->ipv4.sin_port));
307 else
308 return (ippPort());
309}
310
311
22c9029b
MS
312/*
313 * '_httpAddrSetPort()' - Set the port number associated with an address.
314 */
315
316void
317_httpAddrSetPort(http_addr_t *addr, /* I - Address */
318 int port) /* I - Port */
319{
320 if (!addr || port <= 0)
321 return;
322
323#ifdef AF_INET6
324 if (addr->addr.sa_family == AF_INET6)
325 addr->ipv6.sin6_port = htons(port);
326 else
327#endif /* AF_INET6 */
328 if (addr->addr.sa_family == AF_INET)
329 addr->ipv4.sin_port = htons(port);
330}
331
332
ef416fc2 333/*
ecdc0628 334 * 'httpAddrString()' - Convert an address to a numeric string.
ef416fc2 335 *
f3c17241 336 * @since CUPS 1.2/OS X 10.5@
ef416fc2 337 */
338
ecdc0628 339char * /* O - Numeric address string */
340httpAddrString(const http_addr_t *addr, /* I - Address to convert */
341 char *s, /* I - String buffer */
342 int slen) /* I - Length of string */
ef416fc2 343{
e07d4801 344 DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", addr, s, slen));
ef416fc2 345
346 /*
347 * Range check input...
348 */
349
350 if (!addr || !s || slen <= 2)
351 {
352 if (s && slen >= 1)
353 *s = '\0';
354
355 return (NULL);
356 }
357
358#ifdef AF_LOCAL
359 if (addr->addr.sa_family == AF_LOCAL)
771bd8cb
MS
360 {
361 if (addr->un.sun_path[0] == '/')
362 strlcpy(s, addr->un.sun_path, slen);
363 else
364 strlcpy(s, "localhost", slen);
365 }
ef416fc2 366 else
367#endif /* AF_LOCAL */
b423cd4c 368 if (addr->addr.sa_family == AF_INET)
ef416fc2 369 {
b423cd4c 370 unsigned temp; /* Temporary address */
ef416fc2 371
372
b423cd4c 373 temp = ntohl(addr->ipv4.sin_addr.s_addr);
374
375 snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
376 (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
377 }
378#ifdef AF_INET6
379 else if (addr->addr.sa_family == AF_INET6)
380 {
82f97232
MS
381 char *sptr, /* Pointer into string */
382 temps[64]; /* Temporary string for address */
383
b423cd4c 384# ifdef HAVE_GETNAMEINFO
82f97232 385 if (getnameinfo(&addr->addr, httpAddrLength(addr), temps, sizeof(temps),
b423cd4c 386 NULL, 0, NI_NUMERICHOST))
ef416fc2 387 {
388 /*
389 * If we get an error back, then the address type is not supported
390 * and we should zero out the buffer...
391 */
392
393 s[0] = '\0';
394
395 return (NULL);
396 }
82f97232
MS
397 else if ((sptr = strchr(temps, '%')) != NULL)
398 {
399 /*
400 * Convert "%zone" to "+zone" to match URI form...
401 */
402
403 *sptr = '+';
404 }
405
b423cd4c 406# else
b423cd4c 407 int i; /* Looping var */
408 unsigned temp; /* Current value */
409 const char *prefix; /* Prefix for address */
410
411
412 prefix = "";
82f97232 413 for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++)
ef416fc2 414 {
b423cd4c 415 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
ef416fc2 416
82f97232
MS
417 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
418 (temp >> 16) & 0xffff);
b423cd4c 419 prefix = ":";
b423cd4c 420 sptr += strlen(sptr);
ef416fc2 421
b423cd4c 422 temp &= 0xffff;
ef416fc2 423
b423cd4c 424 if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1])
425 {
82f97232 426 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix, temp);
ef416fc2 427 sptr += strlen(sptr);
ef416fc2 428 }
b423cd4c 429 }
430
431 if (i < 4)
432 {
433 while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i])
434 i ++;
ef416fc2 435
436 if (i < 4)
437 {
82f97232 438 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s:", prefix);
b423cd4c 439 prefix = ":";
b423cd4c 440 sptr += strlen(sptr);
ef416fc2 441
b423cd4c 442 for (; i < 4; i ++)
ef416fc2 443 {
b423cd4c 444 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
ef416fc2 445
82f97232
MS
446 if ((temp & 0xffff0000) ||
447 (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1]))
ef416fc2 448 {
82f97232
MS
449 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
450 (temp >> 16) & 0xffff);
ef416fc2 451 sptr += strlen(sptr);
b423cd4c 452 }
ef416fc2 453
82f97232
MS
454 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
455 temp & 0xffff);
b423cd4c 456 sptr += strlen(sptr);
ef416fc2 457 }
458 }
b423cd4c 459 else if (sptr == s)
460 {
461 /*
462 * Empty address...
463 */
ef416fc2 464
82f97232 465 strlcpy(temps, "::", sizeof(temps));
b423cd4c 466 }
467 else
468 {
469 /*
470 * Empty at end...
471 */
ef416fc2 472
82f97232 473 strlcpy(sptr, "::", sizeof(temps) - (sptr - temps));
b423cd4c 474 }
ef416fc2 475 }
b423cd4c 476# endif /* HAVE_GETNAMEINFO */
82f97232
MS
477
478 /*
479 * Add "[v1." and "]" around IPv6 address to convert to URI form.
480 */
481
482 snprintf(s, slen, "[v1.%s]", temps);
ef416fc2 483 }
b423cd4c 484#endif /* AF_INET6 */
485 else
486 strlcpy(s, "UNKNOWN", slen);
ef416fc2 487
e07d4801 488 DEBUG_printf(("1httpAddrString: returning \"%s\"...", s));
ef416fc2 489
490 return (s);
491}
492
493
494/*
495 * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
496 * address records for the specified name.
497 *
498 * @deprecated@
499 */
500
501struct hostent * /* O - Host entry */
502httpGetHostByName(const char *name) /* I - Hostname or IP address */
503{
504 const char *nameptr; /* Pointer into name */
505 unsigned ip[4]; /* IP address components */
506 _cups_globals_t *cg = _cupsGlobals();
507 /* Pointer to library globals */
508
509
e07d4801 510 DEBUG_printf(("httpGetHostByName(name=\"%s\")", name));
ef416fc2 511
512 /*
513 * Avoid lookup delays and configuration problems when connecting
514 * to the localhost address...
515 */
516
517 if (!strcmp(name, "localhost"))
518 name = "127.0.0.1";
519
520 /*
521 * This function is needed because some operating systems have a
522 * buggy implementation of gethostbyname() that does not support
523 * IP addresses. If the first character of the name string is a
524 * number, then sscanf() is used to extract the IP components.
525 * We then pack the components into an IPv4 address manually,
526 * since the inet_aton() function is deprecated. We use the
527 * htonl() macro to get the right byte order for the address.
528 *
529 * We also support domain sockets when supported by the underlying
530 * OS...
531 */
532
533#ifdef AF_LOCAL
534 if (name[0] == '/')
535 {
536 /*
537 * A domain socket address, so make an AF_LOCAL entry and return it...
538 */
539
540 cg->hostent.h_name = (char *)name;
541 cg->hostent.h_aliases = NULL;
542 cg->hostent.h_addrtype = AF_LOCAL;
543 cg->hostent.h_length = strlen(name) + 1;
544 cg->hostent.h_addr_list = cg->ip_ptrs;
545 cg->ip_ptrs[0] = (char *)name;
546 cg->ip_ptrs[1] = NULL;
547
e07d4801 548 DEBUG_puts("1httpGetHostByName: returning domain socket address...");
ef416fc2 549
550 return (&cg->hostent);
551 }
552#endif /* AF_LOCAL */
553
554 for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
555
556 if (!*nameptr)
557 {
558 /*
559 * We have an IPv4 address; break it up and provide the host entry
560 * to the caller.
561 */
562
563 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
564 return (NULL); /* Must have 4 numbers */
565
566 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
567 return (NULL); /* Invalid byte ranges! */
568
569 cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
570 ip[3]));
571
572 /*
573 * Fill in the host entry and return it...
574 */
575
576 cg->hostent.h_name = (char *)name;
577 cg->hostent.h_aliases = NULL;
578 cg->hostent.h_addrtype = AF_INET;
579 cg->hostent.h_length = 4;
580 cg->hostent.h_addr_list = cg->ip_ptrs;
581 cg->ip_ptrs[0] = (char *)&(cg->ip_addr);
582 cg->ip_ptrs[1] = NULL;
583
e07d4801 584 DEBUG_puts("1httpGetHostByName: returning IPv4 address...");
ef416fc2 585
586 return (&cg->hostent);
587 }
588 else
589 {
590 /*
591 * Use the gethostbyname() function to get the IPv4 address for
592 * the name...
593 */
594
e07d4801 595 DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)...");
ef416fc2 596
597 return (gethostbyname(name));
598 }
599}
600
601
602/*
757d2cad 603 * 'httpGetHostname()' - Get the FQDN for the connection or local system.
ef416fc2 604 *
757d2cad 605 * When "http" points to a connected socket, return the hostname or
606 * address that was used in the call to httpConnect() or httpConnectEncrypt().
607 * Otherwise, return the FQDN for the local system using both gethostname()
608 * and gethostbyname() to get the local hostname with domain.
ef416fc2 609 *
f3c17241 610 * @since CUPS 1.2/OS X 10.5@
ef416fc2 611 */
612
757d2cad 613const char * /* O - FQDN for connection or system */
614httpGetHostname(http_t *http, /* I - HTTP connection or NULL */
615 char *s, /* I - String buffer for name */
616 int slen) /* I - Size of buffer */
ef416fc2 617{
89d46774 618 if (!s || slen <= 1)
619 return (NULL);
620
757d2cad 621 if (http)
480ef0fe 622 {
623 if (http->hostname[0] == '/')
624 strlcpy(s, "localhost", slen);
625 else
626 strlcpy(s, http->hostname, slen);
627 }
757d2cad 628 else
ef416fc2 629 {
630 /*
757d2cad 631 * Get the hostname...
ef416fc2 632 */
633
89d46774 634 if (gethostname(s, slen) < 0)
635 strlcpy(s, "localhost", slen);
757d2cad 636
637 if (!strchr(s, '.'))
638 {
0837b7e8 639#ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
1106b00e
MS
640 /*
641 * The hostname is not a FQDN, so use the local hostname from the
642 * SystemConfiguration framework...
643 */
644
645 SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault,
646 CFSTR("libcups"), NULL, NULL);
647 /* System configuration data */
648 CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL;
649 /* Local host name */
650 char localStr[1024]; /* Local host name C string */
651
652 if (local && CFStringGetCString(local, localStr, sizeof(localStr),
653 kCFStringEncodingUTF8))
654 {
655 /*
656 * Append ".local." to the hostname we get...
657 */
658
659 snprintf(s, slen, "%s.local.", localStr);
660 }
661
662 if (local)
663 CFRelease(local);
664 if (sc)
665 CFRelease(sc);
666
667#else
757d2cad 668 /*
669 * The hostname is not a FQDN, so look it up...
670 */
671
1106b00e
MS
672 struct hostent *host; /* Host entry to get FQDN */
673
89d46774 674 if ((host = gethostbyname(s)) != NULL && host->h_name)
1106b00e
MS
675 {
676 /*
677 * Use the resolved hostname...
678 */
679
757d2cad 680 strlcpy(s, host->h_name, slen);
1106b00e 681 }
0837b7e8 682#endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
757d2cad 683 }
ef416fc2 684 }
685
686 /*
687 * Return the hostname with as much domain info as we have...
688 */
689
690 return (s);
691}
692
693
694/*
b19ccc9e 695 * End of "$Id: http-addr.c 7910 2008-09-06 00:25:17Z mike $".
ef416fc2 696 */