Merge changes from CUPS 1.4svn-r7874.
[thirdparty/cups.git] / cups / http-addr.c
CommitLineData
ef416fc2 1/*
2e4ff8af 2 * "$Id: http-addr.c 6814 2007-08-20 20:09:25Z mike $"
ef416fc2 3 *
4 * HTTP address routines for the Common UNIX Printing System (CUPS).
5 *
1ff0402e 6 * Copyright 2007-2008 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.
ef416fc2 22 * httpAddrString() - Convert an IP address to a dotted string.
23 * httpGetHostByName() - Lookup a hostname or IP address, and return
24 * address records for the specified name.
25 * httpGetHostname() - Get the FQDN for the local system.
26 */
27
28/*
29 * Include necessary headers...
30 */
31
32#include "globals.h"
33#include "debug.h"
34#include <stdlib.h>
35#include <stddef.h>
36
37
38/*
39 * 'httpAddrAny()' - Check for the "any" address.
40 *
41 * @since CUPS 1.2@
42 */
43
44int /* O - 1 if "any", 0 otherwise */
45httpAddrAny(const http_addr_t *addr) /* I - Address to check */
46{
89d46774 47 if (!addr)
48 return (0);
49
ef416fc2 50#ifdef AF_INET6
51 if (addr->addr.sa_family == AF_INET6 &&
52 IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
53 return (1);
54#endif /* AF_INET6 */
55
56 if (addr->addr.sa_family == AF_INET &&
57 ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
58 return (1);
59
60 return (0);
61}
62
63
64/*
65 * 'httpAddrEqual()' - Compare two addresses.
66 *
67 * @since CUPS 1.2@
68 */
69
ecdc0628 70int /* O - 1 if equal, 0 if not */
ef416fc2 71httpAddrEqual(const http_addr_t *addr1, /* I - First address */
72 const http_addr_t *addr2) /* I - Second address */
73{
89d46774 74 if (!addr1 && !addr2)
75 return (1);
76
77 if (!addr1 || !addr2)
78 return (0);
79
ef416fc2 80 if (addr1->addr.sa_family != addr2->addr.sa_family)
81 return (0);
82
83#ifdef AF_LOCAL
84 if (addr1->addr.sa_family == AF_LOCAL)
85 return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
86#endif /* AF_LOCAL */
87
88#ifdef AF_INET6
89 if (addr1->addr.sa_family == AF_INET6)
90 return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16));
91#endif /* AF_INET6 */
92
93 return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
94}
95
96
97/*
98 * 'httpAddrLength()' - Return the length of the address in bytes.
99 *
100 * @since CUPS 1.2@
101 */
102
103int /* O - Length in bytes */
104httpAddrLength(const http_addr_t *addr) /* I - Address */
105{
89d46774 106 if (!addr)
107 return (0);
108
ef416fc2 109#ifdef AF_INET6
110 if (addr->addr.sa_family == AF_INET6)
111 return (sizeof(addr->ipv6));
112 else
113#endif /* AF_INET6 */
114#ifdef AF_LOCAL
115 if (addr->addr.sa_family == AF_LOCAL)
116 return (offsetof(struct sockaddr_un, sun_path) +
117 strlen(addr->un.sun_path) + 1);
118 else
119#endif /* AF_LOCAL */
120 if (addr->addr.sa_family == AF_INET)
121 return (sizeof(addr->ipv4));
122 else
123 return (0);
124
125}
126
127
128/*
129 * 'httpAddrLocalhost()' - Check for the local loopback address.
130 *
131 * @since CUPS 1.2@
132 */
133
134int /* O - 1 if local host, 0 otherwise */
135httpAddrLocalhost(
136 const http_addr_t *addr) /* I - Address to check */
137{
89d46774 138 if (!addr)
139 return (1);
140
ef416fc2 141#ifdef AF_INET6
142 if (addr->addr.sa_family == AF_INET6 &&
fa73b229 143 IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
ef416fc2 144 return (1);
145#endif /* AF_INET6 */
146
147#ifdef AF_LOCAL
148 if (addr->addr.sa_family == AF_LOCAL)
149 return (1);
150#endif /* AF_LOCAL */
151
152 if (addr->addr.sa_family == AF_INET &&
153 ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001)
154 return (1);
155
156 return (0);
157}
158
159
160#ifdef __sgi
161# define ADDR_CAST (struct sockaddr *)
162#else
163# define ADDR_CAST (char *)
164#endif /* __sgi */
165
166
167/*
168 * 'httpAddrLookup()' - Lookup the hostname associated with the address.
169 *
170 * @since CUPS 1.2@
171 */
172
ecdc0628 173char * /* O - Host name */
174httpAddrLookup(
175 const http_addr_t *addr, /* I - Address to lookup */
176 char *name, /* I - Host name buffer */
177 int namelen) /* I - Size of name buffer */
ef416fc2 178{
179 DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)\n",
180 addr, name, namelen));
181
182 /*
183 * Range check input...
184 */
185
186 if (!addr || !name || namelen <= 2)
187 {
188 if (name && namelen >= 1)
189 *name = '\0';
190
191 return (NULL);
192 }
193
194#ifdef AF_LOCAL
195 if (addr->addr.sa_family == AF_LOCAL)
196 strlcpy(name, addr->un.sun_path, namelen);
197 else
198#endif /* AF_LOCAL */
199#ifdef HAVE_GETNAMEINFO
200 {
db1f069b
MS
201 /*
202 * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN
203 *
204 * FWIW, I think this is really a bug in the implementation of
205 * getnameinfo(), but falling back on httpAddrString() is easy to
206 * do...
207 */
ef416fc2 208
db1f069b
MS
209 if (getnameinfo(&addr->addr, httpAddrLength(addr), name, namelen,
210 NULL, 0, 0))
211 return (httpAddrString(addr, name, namelen));
ef416fc2 212 }
213#else
214 {
215 struct hostent *host; /* Host from name service */
216
217
218# ifdef AF_INET6
219 if (addr->addr.sa_family == AF_INET6)
220 host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr),
221 sizeof(struct in_addr), AF_INET6);
222 else
223# endif /* AF_INET6 */
224 host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr),
225 sizeof(struct in_addr), AF_INET);
226
227 if (host == NULL)
228 {
229 /*
230 * No hostname, so return the raw address...
231 */
232
233 httpAddrString(addr, name, namelen);
234 return (NULL);
235 }
236
237 strlcpy(name, host->h_name, namelen);
238 }
239#endif /* HAVE_GETNAMEINFO */
240
241 return (name);
242}
243
244
1ff0402e
MS
245/*
246 * '_httpAddrPort()' - Get the port number associated with an address.
247 */
248
249int /* O - Port number */
250_httpAddrPort(http_addr_t *addr) /* I - Address */
251{
5f64df29
MS
252 if (!addr)
253 return (ippPort());
1ff0402e 254#ifdef AF_INET6
5f64df29 255 else if (addr->addr.sa_family == AF_INET6)
1ff0402e 256 return (ntohs(addr->ipv6.sin6_port));
1ff0402e 257#endif /* AF_INET6 */
5f64df29 258 else if (addr->addr.sa_family == AF_INET)
1ff0402e
MS
259 return (ntohs(addr->ipv4.sin_port));
260 else
261 return (ippPort());
262}
263
264
ef416fc2 265/*
ecdc0628 266 * 'httpAddrString()' - Convert an address to a numeric string.
ef416fc2 267 *
268 * @since CUPS 1.2@
269 */
270
ecdc0628 271char * /* O - Numeric address string */
272httpAddrString(const http_addr_t *addr, /* I - Address to convert */
273 char *s, /* I - String buffer */
274 int slen) /* I - Length of string */
ef416fc2 275{
276 DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)\n",
277 addr, s, slen));
278
279 /*
280 * Range check input...
281 */
282
283 if (!addr || !s || slen <= 2)
284 {
285 if (s && slen >= 1)
286 *s = '\0';
287
288 return (NULL);
289 }
290
291#ifdef AF_LOCAL
292 if (addr->addr.sa_family == AF_LOCAL)
293 strlcpy(s, addr->un.sun_path, slen);
294 else
295#endif /* AF_LOCAL */
b423cd4c 296 if (addr->addr.sa_family == AF_INET)
ef416fc2 297 {
b423cd4c 298 unsigned temp; /* Temporary address */
ef416fc2 299
300
b423cd4c 301 temp = ntohl(addr->ipv4.sin_addr.s_addr);
302
303 snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
304 (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
305 }
306#ifdef AF_INET6
307 else if (addr->addr.sa_family == AF_INET6)
308 {
309# ifdef HAVE_GETNAMEINFO
ef416fc2 310 if (getnameinfo(&addr->addr, httpAddrLength(addr), s, slen,
b423cd4c 311 NULL, 0, NI_NUMERICHOST))
ef416fc2 312 {
313 /*
314 * If we get an error back, then the address type is not supported
315 * and we should zero out the buffer...
316 */
317
318 s[0] = '\0';
319
320 return (NULL);
321 }
b423cd4c 322# else
323 char *sptr; /* Pointer into string */
324 int i; /* Looping var */
325 unsigned temp; /* Current value */
326 const char *prefix; /* Prefix for address */
327
328
329 prefix = "";
330 for (sptr = s, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++)
ef416fc2 331 {
b423cd4c 332 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
ef416fc2 333
b423cd4c 334 snprintf(sptr, slen, "%s%x", prefix, (temp >> 16) & 0xffff);
335 prefix = ":";
336 slen -= strlen(sptr);
337 sptr += strlen(sptr);
ef416fc2 338
b423cd4c 339 temp &= 0xffff;
ef416fc2 340
b423cd4c 341 if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1])
342 {
343 snprintf(sptr, slen, "%s%x", prefix, temp);
ef416fc2 344 slen -= strlen(sptr);
345 sptr += strlen(sptr);
ef416fc2 346 }
b423cd4c 347 }
348
349 if (i < 4)
350 {
351 while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i])
352 i ++;
ef416fc2 353
354 if (i < 4)
355 {
b423cd4c 356 snprintf(sptr, slen, "%s:", prefix);
357 prefix = ":";
358 slen -= strlen(sptr);
359 sptr += strlen(sptr);
ef416fc2 360
b423cd4c 361 for (; i < 4; i ++)
ef416fc2 362 {
b423cd4c 363 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
ef416fc2 364
b423cd4c 365 if ((temp & 0xffff0000) || addr->ipv6.sin6_addr.s6_addr32[i - 1])
ef416fc2 366 {
b423cd4c 367 snprintf(sptr, slen, "%s%x", prefix, (temp >> 16) & 0xffff);
ef416fc2 368 slen -= strlen(sptr);
369 sptr += strlen(sptr);
b423cd4c 370 }
ef416fc2 371
b423cd4c 372 snprintf(sptr, slen, "%s%x", prefix, temp & 0xffff);
373 slen -= strlen(sptr);
374 sptr += strlen(sptr);
ef416fc2 375 }
376 }
b423cd4c 377 else if (sptr == s)
378 {
379 /*
380 * Empty address...
381 */
ef416fc2 382
b423cd4c 383 strlcpy(s, "::", slen);
384 sptr = s + 2;
385 slen -= 2;
386 }
387 else
388 {
389 /*
390 * Empty at end...
391 */
ef416fc2 392
b423cd4c 393 strlcpy(sptr, "::", slen);
394 sptr += 2;
395 slen -= 2;
396 }
ef416fc2 397 }
b423cd4c 398# endif /* HAVE_GETNAMEINFO */
ef416fc2 399 }
b423cd4c 400#endif /* AF_INET6 */
401 else
402 strlcpy(s, "UNKNOWN", slen);
ef416fc2 403
404 DEBUG_printf(("httpAddrString: returning \"%s\"...\n", s));
405
406 return (s);
407}
408
409
410/*
411 * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
412 * address records for the specified name.
413 *
414 * @deprecated@
415 */
416
417struct hostent * /* O - Host entry */
418httpGetHostByName(const char *name) /* I - Hostname or IP address */
419{
420 const char *nameptr; /* Pointer into name */
421 unsigned ip[4]; /* IP address components */
422 _cups_globals_t *cg = _cupsGlobals();
423 /* Pointer to library globals */
424
425
426 DEBUG_printf(("httpGetHostByName(name=\"%s\")\n", name));
427
428 /*
429 * Avoid lookup delays and configuration problems when connecting
430 * to the localhost address...
431 */
432
433 if (!strcmp(name, "localhost"))
434 name = "127.0.0.1";
435
436 /*
437 * This function is needed because some operating systems have a
438 * buggy implementation of gethostbyname() that does not support
439 * IP addresses. If the first character of the name string is a
440 * number, then sscanf() is used to extract the IP components.
441 * We then pack the components into an IPv4 address manually,
442 * since the inet_aton() function is deprecated. We use the
443 * htonl() macro to get the right byte order for the address.
444 *
445 * We also support domain sockets when supported by the underlying
446 * OS...
447 */
448
449#ifdef AF_LOCAL
450 if (name[0] == '/')
451 {
452 /*
453 * A domain socket address, so make an AF_LOCAL entry and return it...
454 */
455
456 cg->hostent.h_name = (char *)name;
457 cg->hostent.h_aliases = NULL;
458 cg->hostent.h_addrtype = AF_LOCAL;
459 cg->hostent.h_length = strlen(name) + 1;
460 cg->hostent.h_addr_list = cg->ip_ptrs;
461 cg->ip_ptrs[0] = (char *)name;
462 cg->ip_ptrs[1] = NULL;
463
464 DEBUG_puts("httpGetHostByName: returning domain socket address...");
465
466 return (&cg->hostent);
467 }
468#endif /* AF_LOCAL */
469
470 for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
471
472 if (!*nameptr)
473 {
474 /*
475 * We have an IPv4 address; break it up and provide the host entry
476 * to the caller.
477 */
478
479 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
480 return (NULL); /* Must have 4 numbers */
481
482 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
483 return (NULL); /* Invalid byte ranges! */
484
485 cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
486 ip[3]));
487
488 /*
489 * Fill in the host entry and return it...
490 */
491
492 cg->hostent.h_name = (char *)name;
493 cg->hostent.h_aliases = NULL;
494 cg->hostent.h_addrtype = AF_INET;
495 cg->hostent.h_length = 4;
496 cg->hostent.h_addr_list = cg->ip_ptrs;
497 cg->ip_ptrs[0] = (char *)&(cg->ip_addr);
498 cg->ip_ptrs[1] = NULL;
499
500 DEBUG_puts("httpGetHostByName: returning IPv4 address...");
501
502 return (&cg->hostent);
503 }
504 else
505 {
506 /*
507 * Use the gethostbyname() function to get the IPv4 address for
508 * the name...
509 */
510
511 DEBUG_puts("httpGetHostByName: returning domain lookup address(es)...");
512
513 return (gethostbyname(name));
514 }
515}
516
517
518/*
757d2cad 519 * 'httpGetHostname()' - Get the FQDN for the connection or local system.
ef416fc2 520 *
757d2cad 521 * When "http" points to a connected socket, return the hostname or
522 * address that was used in the call to httpConnect() or httpConnectEncrypt().
523 * Otherwise, return the FQDN for the local system using both gethostname()
524 * and gethostbyname() to get the local hostname with domain.
ef416fc2 525 *
526 * @since CUPS 1.2@
527 */
528
757d2cad 529const char * /* O - FQDN for connection or system */
530httpGetHostname(http_t *http, /* I - HTTP connection or NULL */
531 char *s, /* I - String buffer for name */
532 int slen) /* I - Size of buffer */
ef416fc2 533{
534 struct hostent *host; /* Host entry to get FQDN */
535
536
89d46774 537 if (!s || slen <= 1)
538 return (NULL);
539
757d2cad 540 if (http)
480ef0fe 541 {
542 if (http->hostname[0] == '/')
543 strlcpy(s, "localhost", slen);
544 else
545 strlcpy(s, http->hostname, slen);
546 }
757d2cad 547 else
ef416fc2 548 {
549 /*
757d2cad 550 * Get the hostname...
ef416fc2 551 */
552
89d46774 553 if (gethostname(s, slen) < 0)
554 strlcpy(s, "localhost", slen);
757d2cad 555
556 if (!strchr(s, '.'))
557 {
558 /*
559 * The hostname is not a FQDN, so look it up...
560 */
561
89d46774 562 if ((host = gethostbyname(s)) != NULL && host->h_name)
757d2cad 563 strlcpy(s, host->h_name, slen);
564 }
ef416fc2 565 }
566
567 /*
568 * Return the hostname with as much domain info as we have...
569 */
570
571 return (s);
572}
573
574
575/*
2e4ff8af 576 * End of "$Id: http-addr.c 6814 2007-08-20 20:09:25Z mike $".
ef416fc2 577 */